Add a test that puts all components on an entity and checks for no exceptions (#1815)

* Add test that puts all components on an entity and checks for no exceptions

Also fix all the exceptions that happened because of this

* Add comments to the test

* Fix nullable errors

* Fix more nullable errors

* More nullable error fixes

* Unignore basic actor component

* Fix more nullable errors

* NULLABLE ERROR

* Add string interpolation

* Merge if checks

* Remove redundant pragma warning disable 649

* Address reviews

* Remove null wrappers around TryGetComponent

* Merge conflict fixes

* APC battery component error fix

* Fix power test

* Fix atmos mapgrid usages
This commit is contained in:
DrSmugleaf
2020-08-22 22:29:20 +02:00
committed by GitHub
parent c8178550b8
commit b9196d0a10
84 changed files with 1790 additions and 1123 deletions

View File

@@ -17,9 +17,7 @@ namespace Content.Client.GameObjects.Components.Body
[ComponentReference(typeof(IBodyManagerComponent))] [ComponentReference(typeof(IBodyManagerComponent))]
public class BodyManagerComponent : SharedBodyManagerComponent, IClientDraggable public class BodyManagerComponent : SharedBodyManagerComponent, IClientDraggable
{ {
#pragma warning disable 649
[Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!;
#pragma warning restore 649
public bool ClientCanDropOn(CanDropEventArgs eventArgs) public bool ClientCanDropOn(CanDropEventArgs eventArgs)
{ {

View File

@@ -27,13 +27,9 @@ namespace Content.Client.GameObjects.Components.Instruments
/// </summary> /// </summary>
public event Action? OnMidiPlaybackEnded; public event Action? OnMidiPlaybackEnded;
#pragma warning disable 649
[Dependency] private readonly IMidiManager _midiManager = default!; [Dependency] private readonly IMidiManager _midiManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IClientNetManager _netManager = default!; [Dependency] private readonly IClientNetManager _netManager = default!;
#pragma warning restore 649
private IMidiRenderer? _renderer; private IMidiRenderer? _renderer;

View File

@@ -19,9 +19,7 @@ namespace Content.Client.GameObjects.Components.Items
{ {
private HandsGui? _gui; private HandsGui? _gui;
#pragma warning disable 649
[Dependency] private readonly IGameHud _gameHud = default!; [Dependency] private readonly IGameHud _gameHud = default!;
#pragma warning restore 649
/// <inheritdoc /> /// <inheritdoc />
private readonly List<Hand> _hands = new List<Hand>(); private readonly List<Hand> _hands = new List<Hand>();

View File

@@ -1,16 +1,11 @@
using System.IO; using System.Threading.Tasks;
using System.Threading.Tasks;
using Content.Server.GameObjects.Components.Doors; using Content.Server.GameObjects.Components.Doors;
using Content.Shared.Physics;
using NUnit.Framework; using NUnit.Framework;
using Robust.Server.Console.Commands;
using Robust.Shared.GameObjects.Components; using Robust.Shared.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map; using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Physics; using Robust.Shared.Physics;
using Robust.Shared.Prototypes;
using static Content.Server.GameObjects.Components.Doors.ServerDoorComponent; using static Content.Server.GameObjects.Components.Doors.ServerDoorComponent;
namespace Content.IntegrationTests.Tests.Doors namespace Content.IntegrationTests.Tests.Doors

View File

@@ -1,5 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using NUnit.Framework; using NUnit.Framework;
using Robust.Server.Interfaces.Maps; using Robust.Server.Interfaces.Maps;
@@ -11,6 +14,7 @@ using Robust.Shared.Log;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Logger = Robust.Shared.Log.Logger;
namespace Content.IntegrationTests.Tests namespace Content.IntegrationTests.Tests
{ {
@@ -30,7 +34,7 @@ namespace Content.IntegrationTests.Tests
var pauseMan = server.ResolveDependency<IPauseManager>(); var pauseMan = server.ResolveDependency<IPauseManager>();
var prototypes = new List<EntityPrototype>(); var prototypes = new List<EntityPrototype>();
IMapGrid grid = default; IMapGrid grid = default;
IEntity testEntity = null; IEntity testEntity;
//Build up test environment //Build up test environment
server.Post(() => server.Post(() =>
@@ -59,7 +63,7 @@ namespace Content.IntegrationTests.Tests
{ {
try try
{ {
Logger.LogS(LogLevel.Debug, "EntityTest", "Testing: " + prototype.ID); Logger.LogS(LogLevel.Debug, "EntityTest", $"Testing: {prototype.ID}");
testEntity = entityMan.SpawnEntity(prototype.ID, testLocation); testEntity = entityMan.SpawnEntity(prototype.ID, testLocation);
server.RunTicks(2); server.RunTicks(2);
Assert.That(testEntity.Initialized); Assert.That(testEntity.Initialized);
@@ -69,8 +73,8 @@ namespace Content.IntegrationTests.Tests
//Fail any exceptions thrown on spawn //Fail any exceptions thrown on spawn
catch (Exception e) catch (Exception e)
{ {
Logger.LogS(LogLevel.Error, "EntityTest", "Entity '" + prototype.ID + "' threw: " + e.Message); Logger.LogS(LogLevel.Error, "EntityTest", $"Entity '{prototype.ID}' threw: {e.Message}");
//Assert.Fail(); Assert.Fail();
throw; throw;
} }
} }
@@ -101,5 +105,125 @@ namespace Content.IntegrationTests.Tests
await client.WaitIdleAsync(); await client.WaitIdleAsync();
} }
[Test]
public async Task AllComponentsOneEntityDeleteTest()
{
var skipComponents = new[]
{
"DebugExceptionOnAdd", // Debug components that explicitly throw exceptions
"DebugExceptionExposeData",
"DebugExceptionInitialize",
"DebugExceptionStartup",
"Map", // We aren't testing a map entity in this test
"MapGrid"
};
var testEntity = @"
- type: entity
id: AllComponentsOneEntityDeleteTestEntity";
var server = StartServerDummyTicker();
await server.WaitIdleAsync();
var mapManager = server.ResolveDependency<IMapManager>();
var entityManager = server.ResolveDependency<IEntityManager>();
var mapLoader = server.ResolveDependency<IMapLoader>();
var pauseManager = server.ResolveDependency<IPauseManager>();
var componentFactory = server.ResolveDependency<IComponentFactory>();
var prototypeManager = server.ResolveDependency<IPrototypeManager>();
IMapGrid grid = default;
server.Post(() =>
{
// Load test entity
using var reader = new StringReader(testEntity);
prototypeManager.LoadFromStream(reader);
// Load test map
var mapId = mapManager.CreateMap();
pauseManager.AddUninitializedMap(mapId);
grid = mapLoader.LoadBlueprint(mapId, "Maps/stationstation.yml");
pauseManager.DoMapInitialize(mapId);
});
var distinctComponents = new List<(List<Type> components, List<Type> references)>
{
(new List<Type>(), new List<Type>())
};
// Split components into groups, ensuring that their references don't conflict
foreach (var type in componentFactory.AllRegisteredTypes)
{
var registration = componentFactory.GetRegistration(type);
for (var i = 0; i < distinctComponents.Count; i++)
{
var distinct = distinctComponents[i];
if (distinct.references.Intersect(registration.References).Any())
{
// Ensure the next list if this one has conflicting references
if (i + 1 >= distinctComponents.Count)
{
distinctComponents.Add((new List<Type>(), new List<Type>()));
}
continue;
}
// Add the component and its references if no conflicting references were found
distinct.components.Add(type);
distinct.references.AddRange(registration.References);
}
}
// Sanity check
Assert.That(distinctComponents, Is.Not.Empty);
server.Assert(() =>
{
Assert.DoesNotThrow(() =>
{
foreach (var distinct in distinctComponents)
{
var testLocation = new GridCoordinates(new Vector2(0, 0), grid);
var entity = entityManager.SpawnEntity("AllComponentsOneEntityDeleteTestEntity", testLocation);
Assert.That(entity.Initialized);
foreach (var type in distinct.components)
{
var component = (Component) componentFactory.GetComponent(type);
// If the entity already has this component, if it was ensured or added by another
if (entity.HasComponent(component.GetType()))
{
continue;
}
// If this component is ignored
if (skipComponents.Contains(component.Name))
{
continue;
}
component.Owner = entity;
Logger.LogS(LogLevel.Debug, "EntityTest", $"Adding component: {component.Name}");
entityManager.ComponentManager.AddComponent(entity, component);
}
server.RunTicks(48); // Run one full second on the server
entityManager.DeleteEntity(entity.Uid);
}
});
});
await server.WaitIdleAsync();
}
} }
} }

View File

@@ -127,6 +127,7 @@ namespace Content.IntegrationTests.Tests
Assert.That(apcEnt.TryGetComponent<ApcComponent>(out var apc)); Assert.That(apcEnt.TryGetComponent<ApcComponent>(out var apc));
Assert.That(apcExtensionEnt.TryGetComponent<PowerProviderComponent>(out var provider)); Assert.That(apcExtensionEnt.TryGetComponent<PowerProviderComponent>(out var provider));
Assert.That(powerReceiverEnt.TryGetComponent(out receiver)); Assert.That(powerReceiverEnt.TryGetComponent(out receiver));
Assert.NotNull(apc.Battery);
provider.PowerTransferRange = 5; //arbitrary range to reach receiver provider.PowerTransferRange = 5; //arbitrary range to reach receiver
receiver.PowerReceptionRange = 5; //arbitrary range to reach provider receiver.PowerReceptionRange = 5; //arbitrary range to reach provider

View File

@@ -20,10 +20,8 @@ namespace Content.Server.Atmos
[RegisterComponent] [RegisterComponent]
public class GasSprayerComponent : Component, IAfterInteract public class GasSprayerComponent : Component, IAfterInteract
{ {
#pragma warning disable 649
[Dependency] private readonly IServerNotifyManager _notifyManager = default!; [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
[Dependency] private readonly IServerEntityManager _serverEntityManager = default!; [Dependency] private readonly IServerEntityManager _serverEntityManager = default!;
#pragma warning restore 649
//TODO: create a function that can create a gas based on a solution mix //TODO: create a function that can create a gas based on a solution mix
public override string Name => "GasSprayer"; public override string Name => "GasSprayer";

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic; #nullable enable
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Items.Storage;
using Content.Server.Interfaces; using Content.Server.Interfaces;
@@ -15,6 +16,7 @@ using Robust.Shared.IoC;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Log; using Robust.Shared.Log;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Access namespace Content.Server.GameObjects.Components.Access
{ {
@@ -22,16 +24,19 @@ namespace Content.Server.GameObjects.Components.Access
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
public class IdCardConsoleComponent : SharedIdCardConsoleComponent, IActivate public class IdCardConsoleComponent : SharedIdCardConsoleComponent, IActivate
{ {
#pragma warning disable 649 [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
[Dependency] private readonly IServerNotifyManager _notifyManager; [Dependency] private readonly ILocalizationManager _localizationManager = default!;
[Dependency] private readonly ILocalizationManager _localizationManager; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager;
#pragma warning restore 649
private BoundUserInterface _userInterface; private ContainerSlot _privilegedIdContainer = default!;
private ContainerSlot _privilegedIdContainer; private ContainerSlot _targetIdContainer = default!;
private ContainerSlot _targetIdContainer;
private AccessReader _accessReader; [ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(IdCardConsoleUiKey.Key, out var boundUi)
? boundUi
: null;
public override void Initialize() public override void Initialize()
{ {
@@ -40,16 +45,30 @@ namespace Content.Server.GameObjects.Components.Access
_privilegedIdContainer = ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-privilegedId", Owner); _privilegedIdContainer = ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-privilegedId", Owner);
_targetIdContainer = ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-targetId", Owner); _targetIdContainer = ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-targetId", Owner);
_accessReader = Owner.GetComponent<AccessReader>(); if (!Owner.EnsureComponent(out AccessReader _))
{
Logger.Warning($"Entity {Owner} at {Owner.Transform.MapPosition} didn't have a {nameof(AccessReader)}");
}
if (UserInterface == null)
{
Logger.Warning($"Entity {Owner} at {Owner.Transform.MapPosition} doesn't have a {nameof(ServerUserInterfaceComponent)}");
}
else
{
UserInterface.OnReceiveMessage += OnUiReceiveMessage;
}
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(IdCardConsoleUiKey.Key);
_userInterface.OnReceiveMessage += OnUiReceiveMessage;
UpdateUserInterface(); UpdateUserInterface();
} }
private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj) private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj)
{ {
if (obj.Session.AttachedEntity == null)
{
return;
}
switch (obj.Message) switch (obj.Message)
{ {
case IdButtonPressedMessage msg: case IdButtonPressedMessage msg:
@@ -72,13 +91,19 @@ namespace Content.Server.GameObjects.Components.Access
} }
/// <summary> /// <summary>
/// Returns true if there is an ID in <see cref="_privilegedIdContainer"/> and said ID satisfies the requirements of <see cref="_accessReader"/>. /// Returns true if there is an ID in <see cref="_privilegedIdContainer"/> and said ID satisfies the requirements of <see cref="AccessReader"/>.
/// </summary> /// </summary>
private bool PrivilegedIdIsAuthorized() private bool PrivilegedIdIsAuthorized()
{ {
var privilegedIdEntity = _privilegedIdContainer.ContainedEntity; if (!Owner.TryGetComponent(out AccessReader? reader))
return privilegedIdEntity != null && _accessReader.IsAllowed(privilegedIdEntity); {
return true;
} }
var privilegedIdEntity = _privilegedIdContainer.ContainedEntity;
return privilegedIdEntity != null && reader.IsAllowed(privilegedIdEntity);
}
/// <summary> /// <summary>
/// Called when the "Submit" button in the UI gets pressed. /// Called when the "Submit" button in the UI gets pressed.
/// Writes data passed from the UI into the ID stored in <see cref="_targetIdContainer"/>, if present. /// Writes data passed from the UI into the ID stored in <see cref="_targetIdContainer"/>, if present.
@@ -110,7 +135,7 @@ namespace Content.Server.GameObjects.Components.Access
/// </summary> /// </summary>
private void HandleId(IEntity user, ContainerSlot container) private void HandleId(IEntity user, ContainerSlot container)
{ {
if (!user.TryGetComponent(out IHandsComponent hands)) if (!user.TryGetComponent(out IHandsComponent? hands))
{ {
_notifyManager.PopupMessage(Owner.Transform.GridPosition, user, _localizationManager.GetString("You have no hands.")); _notifyManager.PopupMessage(Owner.Transform.GridPosition, user, _localizationManager.GetString("You have no hands."));
return; return;
@@ -133,7 +158,13 @@ namespace Content.Server.GameObjects.Components.Access
{ {
return; return;
} }
if(!hands.Drop(hands.ActiveHand, container))
if (hands.ActiveHand == null)
{
return;
}
if (!hands.Drop(hands.ActiveHand, container))
{ {
_notifyManager.PopupMessage(Owner.Transform.GridPosition, user, _localizationManager.GetString("You can't let go of the ID card!")); _notifyManager.PopupMessage(Owner.Transform.GridPosition, user, _localizationManager.GetString("You can't let go of the ID card!"));
return; return;
@@ -185,17 +216,17 @@ namespace Content.Server.GameObjects.Components.Access
_privilegedIdContainer.ContainedEntity?.Name ?? "", _privilegedIdContainer.ContainedEntity?.Name ?? "",
_targetIdContainer.ContainedEntity?.Name ?? ""); _targetIdContainer.ContainedEntity?.Name ?? "");
} }
_userInterface.SetState(newState); UserInterface?.SetState(newState);
} }
public void Activate(ActivateEventArgs eventArgs) public void Activate(ActivateEventArgs eventArgs)
{ {
if(!eventArgs.User.TryGetComponent(out IActorComponent actor)) if(!eventArgs.User.TryGetComponent(out IActorComponent? actor))
{ {
return; return;
} }
_userInterface.Open(actor.playerSession); UserInterface?.Open(actor.playerSession);
} }
} }
} }

View File

@@ -1,9 +1,10 @@
using System; #nullable enable
using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems;
using Robust.Server.Interfaces.GameObjects; using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Transform; using Robust.Shared.GameObjects.Components.Transform;
using Robust.Shared.GameObjects.Systems; using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Log;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
@@ -13,7 +14,6 @@ namespace Content.Server.GameObjects.Components.Atmos
[RegisterComponent] [RegisterComponent]
public class AirtightComponent : Component, IMapInit public class AirtightComponent : Component, IMapInit
{ {
private SnapGridComponent _snapGrid;
private (GridId, MapIndices) _lastPosition; private (GridId, MapIndices) _lastPosition;
public override string Name => "Airtight"; public override string Name => "Airtight";
@@ -28,7 +28,11 @@ namespace Content.Server.GameObjects.Components.Atmos
set set
{ {
_airBlocked = value; _airBlocked = value;
EntitySystem.Get<AtmosphereSystem>().GetGridAtmosphere(Owner.Transform.GridID)?.Invalidate(_snapGrid.Position);
if (Owner.TryGetComponent(out SnapGridComponent? snapGrid))
{
EntitySystem.Get<AtmosphereSystem>().GetGridAtmosphere(Owner.Transform.GridID)?.Invalidate(snapGrid.Position);
}
} }
} }
@@ -48,19 +52,23 @@ namespace Content.Server.GameObjects.Components.Atmos
base.Initialize(); base.Initialize();
// Using the SnapGrid is critical for the performance of the room builder, and thus if // Using the SnapGrid is critical for the performance of the room builder, and thus if
// it is absent the component will not be airtight. An exception is much easier to track // it is absent the component will not be airtight. A warning is much easier to track
// down than the object magically not being airtight, so throw one if the SnapGrid component // down than the object magically not being airtight, so log one if the SnapGrid component
// is missing. // is missing.
if (!Owner.TryGetComponent(out _snapGrid)) if (!Owner.EnsureComponent(out SnapGridComponent _))
throw new Exception("Airtight entities must have a SnapGrid component"); Logger.Warning($"Entity {Owner} at {Owner.Transform.MapPosition.ToString()} doesn't have a {nameof(SnapGridComponent)}");
UpdatePosition(); UpdatePosition();
} }
public void MapInit() public void MapInit()
{ {
_snapGrid.OnPositionChanged += OnTransformMove; if (Owner.TryGetComponent(out SnapGridComponent? snapGrid))
_lastPosition = (Owner.Transform.GridID, _snapGrid.Position); {
snapGrid.OnPositionChanged += OnTransformMove;
_lastPosition = (Owner.Transform.GridID, snapGrid.Position);
}
UpdatePosition(); UpdatePosition();
} }
@@ -70,11 +78,15 @@ namespace Content.Server.GameObjects.Components.Atmos
_airBlocked = false; _airBlocked = false;
_snapGrid.OnPositionChanged -= OnTransformMove; if (Owner.TryGetComponent(out SnapGridComponent? snapGrid))
{
snapGrid.OnPositionChanged -= OnTransformMove;
if(_fixVacuum) if (_fixVacuum)
EntitySystem.Get<AtmosphereSystem>().GetGridAtmosphere(Owner.Transform.GridID)? EntitySystem.Get<AtmosphereSystem>().GetGridAtmosphere(Owner.Transform.GridID)?
.FixVacuum(_snapGrid.Position); .FixVacuum(snapGrid.Position);
}
UpdatePosition(); UpdatePosition();
} }
@@ -83,15 +95,24 @@ namespace Content.Server.GameObjects.Components.Atmos
{ {
UpdatePosition(_lastPosition.Item1, _lastPosition.Item2); UpdatePosition(_lastPosition.Item1, _lastPosition.Item2);
UpdatePosition(); UpdatePosition();
_lastPosition = (Owner.Transform.GridID, _snapGrid.Position);
if (Owner.TryGetComponent(out SnapGridComponent? snapGrid))
{
_lastPosition = (Owner.Transform.GridID, snapGrid.Position);
}
} }
private void UpdatePosition() => UpdatePosition(Owner.Transform.GridID, _snapGrid.Position); private void UpdatePosition()
{
if (Owner.TryGetComponent(out SnapGridComponent? snapGrid))
{
UpdatePosition(Owner.Transform.GridID, snapGrid.Position);
}
}
private void UpdatePosition(GridId gridId, MapIndices pos) private void UpdatePosition(GridId gridId, MapIndices pos)
{ {
EntitySystem.Get<AtmosphereSystem>().GetGridAtmosphere(gridId)?.Invalidate(pos); EntitySystem.Get<AtmosphereSystem>().GetGridAtmosphere(gridId)?.Invalidate(pos);
} }
} }
} }

View File

@@ -16,30 +16,37 @@ using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Atmos namespace Content.Server.GameObjects.Components.Atmos
{ {
[RegisterComponent] [RegisterComponent]
public class GasAnalyzerComponent : SharedGasAnalyzerComponent, IAfterInteract, IDropped, IUse public class GasAnalyzerComponent : SharedGasAnalyzerComponent, IAfterInteract, IDropped, IUse
{ {
#pragma warning disable 649 [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
[Dependency] private IServerNotifyManager _notifyManager = default!; [Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private IMapManager _mapManager = default!;
#pragma warning restore 649
private BoundUserInterface _userInterface = default!;
private GasAnalyzerDanger _pressureDanger; private GasAnalyzerDanger _pressureDanger;
private float _timeSinceSync; private float _timeSinceSync;
private const float TimeBetweenSyncs = 2f; private const float TimeBetweenSyncs = 2f;
private bool _checkPlayer = false; // Check at the player pos or at some other tile? private bool _checkPlayer = false; // Check at the player pos or at some other tile?
private GridCoordinates? _position; // The tile that we scanned private GridCoordinates? _position; // The tile that we scanned
[ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(GasAnalyzerUiKey.Key, out var boundUi)
? boundUi
: null;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(GasAnalyzerUiKey.Key); if (UserInterface != null)
_userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; {
UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
}
} }
public override ComponentState GetComponentState() public override ComponentState GetComponentState()
@@ -56,7 +63,7 @@ namespace Content.Server.GameObjects.Components.Atmos
{ {
_checkPlayer = true; _checkPlayer = true;
_position = null; _position = null;
_userInterface.Open(session); UserInterface?.Open(session);
UpdateUserInterface(); UpdateUserInterface();
Resync(); Resync();
} }
@@ -71,7 +78,7 @@ namespace Content.Server.GameObjects.Components.Atmos
{ {
_checkPlayer = false; _checkPlayer = false;
_position = pos; _position = pos;
_userInterface.Open(session); UserInterface?.Open(session);
UpdateUserInterface(); UpdateUserInterface();
Resync(); Resync();
} }
@@ -79,7 +86,7 @@ namespace Content.Server.GameObjects.Components.Atmos
public void CloseInterface(IPlayerSession session) public void CloseInterface(IPlayerSession session)
{ {
_position = null; _position = null;
_userInterface.Close(session); UserInterface?.Close(session);
Resync(); Resync();
} }
@@ -123,10 +130,15 @@ namespace Content.Server.GameObjects.Components.Atmos
private void UpdateUserInterface() private void UpdateUserInterface()
{ {
if (UserInterface == null)
{
return;
}
string? error = null; string? error = null;
// Check if the player is still holding the gas analyzer => if not, don't update // Check if the player is still holding the gas analyzer => if not, don't update
foreach (var session in _userInterface.SubscribedSessions) foreach (var session in UserInterface.SubscribedSessions)
{ {
if (session.AttachedEntity == null) if (session.AttachedEntity == null)
return; return;
@@ -156,7 +168,7 @@ namespace Content.Server.GameObjects.Components.Atmos
if (tile == null) if (tile == null)
{ {
error = "No Atmosphere!"; error = "No Atmosphere!";
_userInterface.SetState( UserInterface.SetState(
new GasAnalyzerBoundUserInterfaceState( new GasAnalyzerBoundUserInterfaceState(
0, 0,
0, 0,
@@ -166,7 +178,7 @@ namespace Content.Server.GameObjects.Components.Atmos
} }
var gases = new List<GasEntry>(); var gases = new List<GasEntry>();
for (int i = 0; i < Atmospherics.TotalNumberOfGases; i++) for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++)
{ {
var gas = Atmospherics.GetGas(i); var gas = Atmospherics.GetGas(i);
@@ -175,7 +187,7 @@ namespace Content.Server.GameObjects.Components.Atmos
gases.Add(new GasEntry(gas.Name, tile.Gases[i], gas.Color)); gases.Add(new GasEntry(gas.Name, tile.Gases[i], gas.Color));
} }
_userInterface.SetState( UserInterface.SetState(
new GasAnalyzerBoundUserInterfaceState( new GasAnalyzerBoundUserInterfaceState(
tile.Pressure, tile.Pressure,
tile.Temperature, tile.Temperature,

View File

@@ -6,16 +6,21 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Atmos namespace Content.Server.GameObjects.Components.Atmos
{ {
[RegisterComponent] [RegisterComponent]
public class GasMixtureComponent : Component public class GasMixtureHolderComponent : Component
{ {
public override string Name => "GasMixture"; public override string Name => "GasMixtureHolder";
[ViewVariables] public GasMixture GasMixture { get; set; } = new GasMixture(); [ViewVariables] public GasMixture GasMixture { get; set; } = new GasMixture();
public override void ExposeData(ObjectSerializer serializer) public override void ExposeData(ObjectSerializer serializer)
{ {
base.ExposeData(serializer); base.ExposeData(serializer);
serializer.DataField(this, x => GasMixture.Volume, "volume", 0f);
serializer.DataReadWriteFunction(
"volume",
0f,
vol => GasMixture.Volume = vol,
() => GasMixture.Volume);
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -50,7 +51,6 @@ namespace Content.Server.GameObjects.Components.Atmos
private float _timer = 0f; private float _timer = 0f;
private Stopwatch _stopwatch = new Stopwatch(); private Stopwatch _stopwatch = new Stopwatch();
public int UpdateCounter { get; private set; } = 0; public int UpdateCounter { get; private set; } = 0;
private IMapGrid _grid;
[ViewVariables] [ViewVariables]
private readonly HashSet<ExcitedGroup> _excitedGroups = new HashSet<ExcitedGroup>(1000); private readonly HashSet<ExcitedGroup> _excitedGroups = new HashSet<ExcitedGroup>(1000);
@@ -89,42 +89,40 @@ namespace Content.Server.GameObjects.Components.Atmos
/// <inheritdoc /> /// <inheritdoc />
public void PryTile(MapIndices indices) public void PryTile(MapIndices indices)
{ {
if (!Owner.TryGetComponent(out IMapGridComponent? mapGridComponent)) return;
if (IsSpace(indices) || IsAirBlocked(indices)) return; if (IsSpace(indices) || IsAirBlocked(indices)) return;
var tile = _grid.GetTileRef(indices).Tile; var mapGrid = mapGridComponent.Grid;
var tile = mapGrid.GetTileRef(indices).Tile;
var tileDefinitionManager = IoCManager.Resolve<ITileDefinitionManager>(); var tileDefinitionManager = IoCManager.Resolve<ITileDefinitionManager>();
var tileDef = (ContentTileDefinition)tileDefinitionManager[tile.TypeId]; var tileDef = (ContentTileDefinition)tileDefinitionManager[tile.TypeId];
var underplating = tileDefinitionManager["underplating"]; var underplating = tileDefinitionManager["underplating"];
_grid.SetTile(indices, new Tile(underplating.TileId)); mapGrid.SetTile(indices, new Tile(underplating.TileId));
//Actually spawn the relevant tile item at the right position and give it some offset to the corner. //Actually spawn the relevant tile item at the right position and give it some offset to the corner.
var tileItem = IoCManager.Resolve<IServerEntityManager>().SpawnEntity(tileDef.ItemDropPrototypeName, new GridCoordinates(indices.X, indices.Y, _grid)); var tileItem = IoCManager.Resolve<IServerEntityManager>().SpawnEntity(tileDef.ItemDropPrototypeName, new GridCoordinates(indices.X, indices.Y, mapGrid));
tileItem.Transform.WorldPosition += (0.2f, 0.2f); tileItem.Transform.WorldPosition += (0.2f, 0.2f);
} }
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_grid = Owner.GetComponent<IMapGridComponent>().Grid;
RepopulateTiles(); RepopulateTiles();
} }
public override void OnAdd() public override void OnAdd()
{ {
base.OnAdd(); base.OnAdd();
_grid = Owner.GetComponent<IMapGridComponent>().Grid;
RepopulateTiles(); RepopulateTiles();
} }
public void RepopulateTiles() public void RepopulateTiles()
{ {
foreach (var tile in _grid.GetAllTiles()) if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return;
foreach (var tile in mapGrid.Grid.GetAllTiles())
{ {
if(!_tiles.ContainsKey(tile.GridIndices)) if(!_tiles.ContainsKey(tile.GridIndices))
_tiles.Add(tile.GridIndices, new TileAtmosphere(this, tile.GridIndex, tile.GridIndices, new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C})); _tiles.Add(tile.GridIndices, new TileAtmosphere(this, tile.GridIndex, tile.GridIndices, new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C}));
@@ -145,6 +143,8 @@ namespace Content.Server.GameObjects.Components.Atmos
private void Revalidate() private void Revalidate()
{ {
if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return;
foreach (var indices in _invalidatedCoords.ToArray()) foreach (var indices in _invalidatedCoords.ToArray())
{ {
var tile = GetTile(indices); var tile = GetTile(indices);
@@ -152,7 +152,7 @@ namespace Content.Server.GameObjects.Components.Atmos
if (tile == null) if (tile == null)
{ {
tile = new TileAtmosphere(this, _grid.Index, indices, new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C}); tile = new TileAtmosphere(this, mapGrid.Grid.Index, indices, new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C});
_tiles[indices] = tile; _tiles[indices] = tile;
} }
@@ -199,8 +199,9 @@ namespace Content.Server.GameObjects.Components.Atmos
/// <inheritdoc /> /// <inheritdoc />
public void FixVacuum(MapIndices indices) public void FixVacuum(MapIndices indices)
{ {
if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return;
var tile = GetTile(indices); var tile = GetTile(indices);
if (tile?.GridIndex != _grid.Index) return; if (tile?.GridIndex != mapGrid.Grid.Index) return;
var adjacent = GetAdjacentTiles(indices); var adjacent = GetAdjacentTiles(indices);
tile.Air = new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C}; tile.Air = new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C};
_tiles[indices] = tile; _tiles[indices] = tile;
@@ -217,16 +218,17 @@ namespace Content.Server.GameObjects.Components.Atmos
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddActiveTile(TileAtmosphere tile) public void AddActiveTile(TileAtmosphere? tile)
{ {
if (tile?.GridIndex != _grid.Index || tile?.Air == null) return; if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return;
if (tile?.GridIndex != mapGrid.Grid.Index || tile?.Air == null) return;
tile.Excited = true; tile.Excited = true;
_activeTiles.Add(tile); _activeTiles.Add(tile);
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RemoveActiveTile(TileAtmosphere tile) public void RemoveActiveTile(TileAtmosphere? tile)
{ {
if (tile == null) return; if (tile == null) return;
_activeTiles.Remove(tile); _activeTiles.Remove(tile);
@@ -236,27 +238,29 @@ namespace Content.Server.GameObjects.Components.Atmos
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddHotspotTile(TileAtmosphere tile) public void AddHotspotTile(TileAtmosphere? tile)
{ {
if (tile?.GridIndex != _grid.Index || tile?.Air == null) return; if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return;
if (tile?.GridIndex != mapGrid.Grid.Index || tile?.Air == null) return;
_hotspotTiles.Add(tile); _hotspotTiles.Add(tile);
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RemoveHotspotTile(TileAtmosphere tile) public void RemoveHotspotTile(TileAtmosphere? tile)
{ {
if (tile == null) return; if (tile == null) return;
_hotspotTiles.Remove(tile); _hotspotTiles.Remove(tile);
} }
public void AddSuperconductivityTile(TileAtmosphere tile) public void AddSuperconductivityTile(TileAtmosphere? tile)
{ {
if (tile?.GridIndex != _grid.Index) return; if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return;
if (tile?.GridIndex != mapGrid.Grid.Index) return;
_superconductivityTiles.Add(tile); _superconductivityTiles.Add(tile);
} }
public void RemoveSuperconductivityTile(TileAtmosphere tile) public void RemoveSuperconductivityTile(TileAtmosphere? tile)
{ {
if (tile == null) return; if (tile == null) return;
_superconductivityTiles.Remove(tile); _superconductivityTiles.Remove(tile);
@@ -264,9 +268,10 @@ namespace Content.Server.GameObjects.Components.Atmos
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddHighPressureDelta(TileAtmosphere tile) public void AddHighPressureDelta(TileAtmosphere? tile)
{ {
if (tile?.GridIndex != _grid.Index) return; if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return;
if (tile?.GridIndex != mapGrid.Grid.Index) return;
_highPressureDelta.Add(tile); _highPressureDelta.Add(tile);
} }
@@ -292,20 +297,22 @@ namespace Content.Server.GameObjects.Components.Atmos
} }
/// <inheritdoc /> /// <inheritdoc />
public TileAtmosphere GetTile(GridCoordinates coordinates) public TileAtmosphere? GetTile(GridCoordinates coordinates)
{ {
return GetTile(coordinates.ToMapIndices(_mapManager)); return GetTile(coordinates.ToMapIndices(_mapManager));
} }
/// <inheritdoc /> /// <inheritdoc />
public TileAtmosphere GetTile(MapIndices indices) public TileAtmosphere? GetTile(MapIndices indices)
{ {
if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return null;
if (_tiles.TryGetValue(indices, out var tile)) return tile; if (_tiles.TryGetValue(indices, out var tile)) return tile;
// We don't have that tile! // We don't have that tile!
if (IsSpace(indices)) if (IsSpace(indices))
{ {
var space = new TileAtmosphere(this, _grid.Index, indices, new GasMixture(int.MaxValue){Temperature = Atmospherics.TCMB}); var space = new TileAtmosphere(this, mapGrid.Grid.Index, indices, new GasMixture(int.MaxValue){Temperature = Atmospherics.TCMB});
space.Air.MarkImmutable(); space.Air.MarkImmutable();
return space; return space;
} }
@@ -324,7 +331,9 @@ namespace Content.Server.GameObjects.Components.Atmos
public bool IsSpace(MapIndices indices) public bool IsSpace(MapIndices indices)
{ {
// TODO ATMOS use ContentTileDefinition to define in YAML whether or not a tile is considered space // TODO ATMOS use ContentTileDefinition to define in YAML whether or not a tile is considered space
return _grid.GetTileRef(indices).Tile.IsEmpty; if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return default;
return mapGrid.Grid.GetTileRef(indices).Tile.IsEmpty;
} }
public Dictionary<Direction, TileAtmosphere> GetAdjacentTiles(MapIndices indices, bool includeAirBlocked = false) public Dictionary<Direction, TileAtmosphere> GetAdjacentTiles(MapIndices indices, bool includeAirBlocked = false)
@@ -334,7 +343,7 @@ namespace Content.Server.GameObjects.Components.Atmos
{ {
var side = indices.Offset(dir); var side = indices.Offset(dir);
var tile = GetTile(side); var tile = GetTile(side);
if(tile?.Air != null || includeAirBlocked) if (tile != null && (tile.Air != null || includeAirBlocked))
sides[dir] = tile; sides[dir] = tile;
} }
@@ -349,7 +358,9 @@ namespace Content.Server.GameObjects.Components.Atmos
/// <inheritdoc /> /// <inheritdoc />
public float GetVolumeForCells(int cellCount) public float GetVolumeForCells(int cellCount)
{ {
return _grid.TileSize * cellCount * Atmospherics.CellVolume; if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return default;
return mapGrid.Grid.TileSize * cellCount * Atmospherics.CellVolume;
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -509,9 +520,11 @@ namespace Content.Server.GameObjects.Components.Atmos
} }
} }
private AirtightComponent GetObstructingComponent(MapIndices indices) private AirtightComponent? GetObstructingComponent(MapIndices indices)
{ {
foreach (var v in _grid.GetSnapGridCell(indices, SnapGridOffset.Center)) if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return default;
foreach (var v in mapGrid.Grid.GetSnapGridCell(indices, SnapGridOffset.Center))
{ {
if (v.Owner.TryGetComponent<AirtightComponent>(out var ac)) if (v.Owner.TryGetComponent<AirtightComponent>(out var ac))
return ac; return ac;
@@ -534,22 +547,24 @@ namespace Content.Server.GameObjects.Components.Atmos
public override void ExposeData(ObjectSerializer serializer) public override void ExposeData(ObjectSerializer serializer)
{ {
base.ExposeData(serializer); base.ExposeData(serializer);
if (serializer.Reading) if (serializer.Reading &&
Owner.TryGetComponent(out IMapGridComponent? mapGrid))
{ {
var gridId = Owner.GetComponent<IMapGridComponent>().Grid.Index; var gridId = mapGrid.Grid.Index;
if (!serializer.TryReadDataField("uniqueMixes", out List<GasMixture> uniqueMixes) || if (!serializer.TryReadDataField("uniqueMixes", out List<GasMixture>? uniqueMixes) ||
!serializer.TryReadDataField("tiles", out Dictionary<MapIndices, int> tiles)) !serializer.TryReadDataField("tiles", out Dictionary<MapIndices, int>? tiles))
return; return;
_tiles.Clear(); _tiles.Clear();
foreach (var (indices, mix) in tiles) foreach (var (indices, mix) in tiles!)
{ {
_tiles.Add(indices, new TileAtmosphere(this, gridId, indices, (GasMixture)uniqueMixes[mix].Clone())); _tiles.Add(indices, new TileAtmosphere(this, gridId, indices, (GasMixture)uniqueMixes![mix].Clone()));
Invalidate(indices); Invalidate(indices);
} }
} else if (serializer.Writing) }
else if (serializer.Writing)
{ {
var uniqueMixes = new List<GasMixture>(); var uniqueMixes = new List<GasMixture>();
var uniqueMixHash = new Dictionary<GasMixture, int>(); var uniqueMixHash = new Dictionary<GasMixture, int>();

View File

@@ -1,4 +1,5 @@
using System.Linq; #nullable enable
using System.Linq;
using Content.Server.GameObjects.Components.Power.ApcNetComponents; using Content.Server.GameObjects.Components.Power.ApcNetComponents;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Server.Interfaces.GameObjects; using Robust.Server.Interfaces.GameObjects;
@@ -19,18 +20,13 @@ namespace Content.Server.GameObjects.Components.BarSign
{ {
public override string Name => "BarSign"; public override string Name => "BarSign";
#pragma warning disable 649 [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager; [Dependency] private readonly IRobustRandom _robustRandom = default!;
[Dependency] private readonly IRobustRandom _robustRandom;
#pragma warning restore 649
private string _currentSign; private string? _currentSign;
private PowerReceiverComponent _power;
private SpriteComponent _sprite;
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public string CurrentSign public string? CurrentSign
{ {
get => _currentSign; get => _currentSign;
set set
@@ -40,6 +36,8 @@ namespace Content.Server.GameObjects.Components.BarSign
} }
} }
private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
private void UpdateSignInfo() private void UpdateSignInfo()
{ {
if (_currentSign == null) if (_currentSign == null)
@@ -53,15 +51,18 @@ namespace Content.Server.GameObjects.Components.BarSign
return; return;
} }
if (!_power.Powered) if (Owner.TryGetComponent(out SpriteComponent? sprite))
{ {
_sprite.LayerSetState(0, "empty"); if (!Powered)
_sprite.LayerSetShader(0, "shaded"); {
sprite.LayerSetState(0, "empty");
sprite.LayerSetShader(0, "shaded");
} }
else else
{ {
_sprite.LayerSetState(0, prototype.Icon); sprite.LayerSetState(0, prototype.Icon);
_sprite.LayerSetShader(0, "unshaded"); sprite.LayerSetShader(0, "unshaded");
}
} }
if (!string.IsNullOrEmpty(prototype.Name)) if (!string.IsNullOrEmpty(prototype.Name))
@@ -80,21 +81,25 @@ namespace Content.Server.GameObjects.Components.BarSign
{ {
base.Initialize(); base.Initialize();
_power = Owner.GetComponent<PowerReceiverComponent>(); if (Owner.TryGetComponent(out PowerReceiverComponent? receiver))
_sprite = Owner.GetComponent<SpriteComponent>(); {
receiver.OnPowerStateChanged += PowerOnOnPowerStateChanged;
_power.OnPowerStateChanged += PowerOnOnPowerStateChanged; }
UpdateSignInfo(); UpdateSignInfo();
} }
public override void OnRemove() public override void OnRemove()
{ {
_power.OnPowerStateChanged -= PowerOnOnPowerStateChanged; if (Owner.TryGetComponent(out PowerReceiverComponent? receiver))
{
receiver.OnPowerStateChanged -= PowerOnOnPowerStateChanged;
}
base.OnRemove(); base.OnRemove();
} }
private void PowerOnOnPowerStateChanged(object sender, PowerStateEventArgs e) private void PowerOnOnPowerStateChanged(object? sender, PowerStateEventArgs e)
{ {
UpdateSignInfo(); UpdateSignInfo();
} }

View File

@@ -1,10 +1,13 @@
using System.Collections.Generic; #nullable enable
using System.Collections.Generic;
using Content.Server.Body; using Content.Server.Body;
using Content.Shared.Body.Scanner; using Content.Shared.Body.Scanner;
using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Interfaces.GameObjects.Components;
using Robust.Server.GameObjects.Components.UserInterface; using Robust.Server.GameObjects.Components.UserInterface;
using Robust.Server.Interfaces.GameObjects; using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Log;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Body namespace Content.Server.GameObjects.Components.Body
{ {
@@ -12,32 +15,44 @@ namespace Content.Server.GameObjects.Components.Body
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
public class BodyScannerComponent : Component, IActivate public class BodyScannerComponent : Component, IActivate
{ {
private BoundUserInterface _userInterface;
public sealed override string Name => "BodyScanner"; public sealed override string Name => "BodyScanner";
[ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(BodyScannerUiKey.Key, out var boundUi)
? boundUi
: null;
void IActivate.Activate(ActivateEventArgs eventArgs) void IActivate.Activate(ActivateEventArgs eventArgs)
{ {
if (!eventArgs.User.TryGetComponent(out IActorComponent actor) || if (!eventArgs.User.TryGetComponent(out IActorComponent? actor) ||
actor.playerSession.AttachedEntity == null) actor.playerSession.AttachedEntity == null)
{ {
return; return;
} }
if (actor.playerSession.AttachedEntity.TryGetComponent(out BodyManagerComponent attempt)) if (actor.playerSession.AttachedEntity.TryGetComponent(out BodyManagerComponent? attempt))
{ {
var state = InterfaceState(attempt.Template, attempt.Parts); var state = InterfaceState(attempt.Template, attempt.Parts);
_userInterface.SetState(state); UserInterface?.SetState(state);
} }
_userInterface.Open(actor.playerSession); UserInterface?.Open(actor.playerSession);
} }
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(BodyScannerUiKey.Key); if (UserInterface == null)
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; {
Logger.Warning($"Entity {Owner} at {Owner.Transform.MapPosition} doesn't have a {nameof(ServerUserInterfaceComponent)}");
}
else
{
UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
}
} }
private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg) { } private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg) { }

View File

@@ -1,12 +1,11 @@
using System.Collections.Generic; #nullable enable
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Content.Server.GameObjects.Components.Body.Circulatory; using Content.Server.GameObjects.Components.Body.Circulatory;
using Content.Server.GameObjects.Components.Chemistry; using Content.Server.GameObjects.Components.Chemistry;
using Content.Shared.Chemistry; using Content.Shared.Chemistry;
using Content.Shared.GameObjects.Components.Nutrition; using Content.Shared.GameObjects.Components.Nutrition;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Log; using Robust.Shared.Log;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
@@ -20,24 +19,20 @@ namespace Content.Server.GameObjects.Components.Body.Digestive
[RegisterComponent] [RegisterComponent]
public class StomachComponent : SharedStomachComponent public class StomachComponent : SharedStomachComponent
{ {
#pragma warning disable 649
[Dependency] private readonly ILocalizationManager _localizationManager;
#pragma warning restore 649
/// <summary> /// <summary>
/// Max volume of internal solution storage /// Max volume of internal solution storage
/// </summary> /// </summary>
public ReagentUnit MaxVolume public ReagentUnit MaxVolume
{ {
get => _stomachContents.MaxVolume; get => Owner.TryGetComponent(out SolutionComponent? solution) ? solution.MaxVolume : ReagentUnit.Zero;
set => _stomachContents.MaxVolume = value; set
{
if (Owner.TryGetComponent(out SolutionComponent? solution))
{
solution.MaxVolume = value;
}
}
} }
/// <summary>
/// Internal solution storage
/// </summary>
[ViewVariables]
private SolutionComponent _stomachContents;
/// <summary> /// <summary>
/// Initial internal solution storage volume /// Initial internal solution storage volume
@@ -68,20 +63,29 @@ namespace Content.Server.GameObjects.Components.Body.Digestive
{ {
base.Startup(); base.Startup();
_stomachContents = Owner.GetComponent<SolutionComponent>(); if (!Owner.EnsureComponent(out SolutionComponent solution))
_stomachContents.MaxVolume = _initialMaxVolume; {
Logger.Warning($"Entity {Owner} at {Owner.Transform.MapPosition} didn't have a {nameof(SolutionComponent)}");
}
solution.MaxVolume = _initialMaxVolume;
} }
public bool TryTransferSolution(Solution solution) public bool TryTransferSolution(Solution solution)
{ {
if (!Owner.TryGetComponent(out SolutionComponent? solutionComponent))
{
return false;
}
// TODO: For now no partial transfers. Potentially change by design // TODO: For now no partial transfers. Potentially change by design
if (solution.TotalVolume + _stomachContents.CurrentVolume > _stomachContents.MaxVolume) if (solution.TotalVolume + solutionComponent.CurrentVolume > solutionComponent.MaxVolume)
{ {
return false; return false;
} }
// Add solution to _stomachContents // Add solution to _stomachContents
_stomachContents.TryAddSolution(solution, false, true); solutionComponent.TryAddSolution(solution, false, true);
// Add each reagent to _reagentDeltas. Used to track how long each reagent has been in the stomach // Add each reagent to _reagentDeltas. Used to track how long each reagent has been in the stomach
foreach (var reagent in solution.Contents) foreach (var reagent in solution.Contents)
{ {
@@ -99,7 +103,8 @@ namespace Content.Server.GameObjects.Components.Body.Digestive
/// <param name="frameTime">The time since the last update in seconds.</param> /// <param name="frameTime">The time since the last update in seconds.</param>
public void Update(float frameTime) public void Update(float frameTime)
{ {
if (!Owner.TryGetComponent(out BloodstreamComponent bloodstream)) if (!Owner.TryGetComponent(out SolutionComponent? solutionComponent) ||
!Owner.TryGetComponent(out BloodstreamComponent? bloodstream))
{ {
return; return;
} }
@@ -114,7 +119,7 @@ namespace Content.Server.GameObjects.Components.Body.Digestive
delta.Increment(frameTime); delta.Increment(frameTime);
if (delta.Lifetime > _digestionDelay) if (delta.Lifetime > _digestionDelay)
{ {
_stomachContents.TryRemoveReagent(delta.ReagentId, delta.Quantity); solutionComponent.TryRemoveReagent(delta.ReagentId, delta.Quantity);
transferSolution.AddReagent(delta.ReagentId, delta.Quantity); transferSolution.AddReagent(delta.ReagentId, delta.Quantity);
_reagentDeltas.Remove(delta); _reagentDeltas.Remove(delta);
} }

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic; #nullable enable
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Content.Shared.Interfaces; using Content.Shared.Interfaces;
using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Interfaces.GameObjects.Components;
@@ -6,6 +7,7 @@ using Content.Server.Body;
using Content.Shared.Body.Surgery; using Content.Shared.Body.Surgery;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Server.GameObjects.Components.UserInterface; using Robust.Server.GameObjects.Components.UserInterface;
using Robust.Server.Interfaces.GameObjects;
using Robust.Server.Interfaces.Player; using Robust.Server.Interfaces.Player;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
@@ -21,20 +23,23 @@ namespace Content.Server.GameObjects.Components.Body
[RegisterComponent] [RegisterComponent]
public class DroppedBodyPartComponent : Component, IAfterInteract, IBodyPartContainer public class DroppedBodyPartComponent : Component, IAfterInteract, IBodyPartContainer
{ {
#pragma warning disable 649 [Dependency] private readonly ISharedNotifyManager _sharedNotifyManager = default!;
[Dependency] private readonly ISharedNotifyManager _sharedNotifyManager;
#pragma warning restore 649
private readonly Dictionary<int, object> _optionsCache = new Dictionary<int, object>(); private readonly Dictionary<int, object> _optionsCache = new Dictionary<int, object>();
private BodyManagerComponent _bodyManagerComponentCache; private BodyManagerComponent? _bodyManagerComponentCache;
private int _idHash; private int _idHash;
private IEntity _performerCache; private IEntity? _performerCache;
private BoundUserInterface _userInterface;
public sealed override string Name => "DroppedBodyPart"; public sealed override string Name => "DroppedBodyPart";
[ViewVariables] public BodyPart ContainedBodyPart { get; private set; } [ViewVariables] public BodyPart ContainedBodyPart { get; private set; } = default!;
[ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(GenericSurgeryUiKey.Key, out var boundUi)
? boundUi
: null;
void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
{ {
@@ -48,7 +53,7 @@ namespace Content.Server.GameObjects.Components.Body
_performerCache = null; _performerCache = null;
_bodyManagerComponentCache = null; _bodyManagerComponentCache = null;
if (eventArgs.Target.TryGetComponent(out BodyManagerComponent bodyManager)) if (eventArgs.Target.TryGetComponent(out BodyManagerComponent? bodyManager))
{ {
SendBodySlotListToUser(eventArgs, bodyManager); SendBodySlotListToUser(eventArgs, bodyManager);
} }
@@ -58,9 +63,10 @@ namespace Content.Server.GameObjects.Components.Body
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>() if (UserInterface != null)
.GetBoundUserInterface(GenericSurgeryUiKey.Key); {
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
}
} }
public void TransferBodyPartData(BodyPart data) public void TransferBodyPartData(BodyPart data)
@@ -68,7 +74,7 @@ namespace Content.Server.GameObjects.Components.Body
ContainedBodyPart = data; ContainedBodyPart = data;
Owner.Name = Loc.GetString(ContainedBodyPart.Name); Owner.Name = Loc.GetString(ContainedBodyPart.Name);
if (Owner.TryGetComponent(out SpriteComponent component)) if (Owner.TryGetComponent(out SpriteComponent? component))
{ {
component.LayerSetRSI(0, data.RSIPath); component.LayerSetRSI(0, data.RSIPath);
component.LayerSetState(0, data.RSIState); component.LayerSetState(0, data.RSIState);
@@ -91,7 +97,7 @@ namespace Content.Server.GameObjects.Components.Body
foreach (var slot in unoccupiedSlots) foreach (var slot in unoccupiedSlots)
{ {
if (!bodyManager.TryGetSlotType(slot, out var typeResult) || if (!bodyManager.TryGetSlotType(slot, out var typeResult) ||
typeResult != ContainedBodyPart.PartType || typeResult != ContainedBodyPart?.PartType ||
!bodyManager.TryGetBodyPartConnections(slot, out var parts)) !bodyManager.TryGetBodyPartConnections(slot, out var parts))
{ {
continue; continue;
@@ -129,7 +135,18 @@ namespace Content.Server.GameObjects.Components.Body
/// </summary> /// </summary>
private void HandleReceiveBodyPartSlot(int key) private void HandleReceiveBodyPartSlot(int key)
{ {
CloseSurgeryUI(_performerCache.GetComponent<BasicActorComponent>().playerSession); if (_performerCache == null ||
!_performerCache.TryGetComponent(out IActorComponent? actor))
{
return;
}
CloseSurgeryUI(actor.playerSession);
if (_bodyManagerComponentCache == null)
{
return;
}
// TODO: sanity checks to see whether user is in range, user is still able-bodied, target is still the same, etc etc // TODO: sanity checks to see whether user is in range, user is still able-bodied, target is still the same, etc etc
if (!_optionsCache.TryGetValue(key, out var targetObject)) if (!_optionsCache.TryGetValue(key, out var targetObject))
@@ -138,34 +155,42 @@ namespace Content.Server.GameObjects.Components.Body
Loc.GetString("You see no useful way to attach {0:theName} anymore.", Owner)); Loc.GetString("You see no useful way to attach {0:theName} anymore.", Owner));
} }
var target = targetObject as string; var target = (string) targetObject!;
string message;
if (_bodyManagerComponentCache.InstallDroppedBodyPart(this, target))
{
message = Loc.GetString("You attach {0:theName}.", ContainedBodyPart);
}
else
{
message = Loc.GetString("You can't attach it!");
}
_sharedNotifyManager.PopupMessage( _sharedNotifyManager.PopupMessage(
_bodyManagerComponentCache.Owner, _bodyManagerComponentCache.Owner,
_performerCache, _performerCache,
!_bodyManagerComponentCache.InstallDroppedBodyPart(this, target) message);
? Loc.GetString("You can't attach it!")
: Loc.GetString("You attach {0:theName}.", ContainedBodyPart));
} }
private void OpenSurgeryUI(IPlayerSession session) private void OpenSurgeryUI(IPlayerSession session)
{ {
_userInterface.Open(session); UserInterface?.Open(session);
} }
private void UpdateSurgeryUIBodyPartSlotRequest(IPlayerSession session, Dictionary<string, int> options) private void UpdateSurgeryUIBodyPartSlotRequest(IPlayerSession session, Dictionary<string, int> options)
{ {
_userInterface.SendMessage(new RequestBodyPartSlotSurgeryUIMessage(options), session); UserInterface?.SendMessage(new RequestBodyPartSlotSurgeryUIMessage(options), session);
} }
private void CloseSurgeryUI(IPlayerSession session) private void CloseSurgeryUI(IPlayerSession session)
{ {
_userInterface.Close(session); UserInterface?.Close(session);
} }
private void CloseAllSurgeryUIs() private void CloseAllSurgeryUIs()
{ {
_userInterface.CloseAll(); UserInterface?.CloseAll();
} }
private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage message) private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage message)

View File

@@ -1,4 +1,4 @@
using System; #nullable enable
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.Body; using Content.Server.Body;
using Content.Server.Body.Mechanisms; using Content.Server.Body.Mechanisms;
@@ -8,14 +8,15 @@ using Content.Shared.Interfaces;
using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Interfaces.GameObjects.Components;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Server.GameObjects.Components.UserInterface; using Robust.Server.GameObjects.Components.UserInterface;
using Robust.Server.Interfaces.GameObjects;
using Robust.Server.Interfaces.Player; using Robust.Server.Interfaces.Player;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Log;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Body namespace Content.Server.GameObjects.Components.Body
@@ -26,24 +27,27 @@ namespace Content.Server.GameObjects.Components.Body
[RegisterComponent] [RegisterComponent]
public class DroppedMechanismComponent : Component, IAfterInteract public class DroppedMechanismComponent : Component, IAfterInteract
{ {
#pragma warning disable 649 [Dependency] private readonly ISharedNotifyManager _sharedNotifyManager = default!;
[Dependency] private readonly ISharedNotifyManager _sharedNotifyManager; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private IPrototypeManager _prototypeManager;
#pragma warning restore 649
public sealed override string Name => "DroppedMechanism"; public sealed override string Name => "DroppedMechanism";
private readonly Dictionary<int, object> _optionsCache = new Dictionary<int, object>(); private readonly Dictionary<int, object> _optionsCache = new Dictionary<int, object>();
private BodyManagerComponent _bodyManagerComponentCache; private BodyManagerComponent? _bodyManagerComponentCache;
private int _idHash; private int _idHash;
private IEntity _performerCache; private IEntity? _performerCache;
private BoundUserInterface _userInterface; [ViewVariables] public Mechanism ContainedMechanism { get; private set; } = default!;
[ViewVariables] public Mechanism ContainedMechanism { get; private set; } [ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(GenericSurgeryUiKey.Key, out var boundUi)
? boundUi
: null;
void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
{ {
@@ -63,12 +67,7 @@ namespace Content.Server.GameObjects.Components.Body
} }
else if (eventArgs.Target.TryGetComponent<DroppedBodyPartComponent>(out var droppedBodyPart)) else if (eventArgs.Target.TryGetComponent<DroppedBodyPartComponent>(out var droppedBodyPart))
{ {
if (droppedBodyPart.ContainedBodyPart == null) DebugTools.AssertNotNull(droppedBodyPart.ContainedBodyPart);
{
Logger.Debug(
"Installing a mechanism was attempted on an IEntity with a DroppedBodyPartComponent that doesn't have a BodyPart in it!");
throw new InvalidOperationException("A DroppedBodyPartComponent exists without a BodyPart in it!");
}
if (!droppedBodyPart.ContainedBodyPart.TryInstallDroppedMechanism(this)) if (!droppedBodyPart.ContainedBodyPart.TryInstallDroppedMechanism(this))
{ {
@@ -82,9 +81,10 @@ namespace Content.Server.GameObjects.Components.Body
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>() if (UserInterface != null)
.GetBoundUserInterface(GenericSurgeryUiKey.Key); {
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
}
} }
public void InitializeDroppedMechanism(Mechanism data) public void InitializeDroppedMechanism(Mechanism data)
@@ -92,7 +92,7 @@ namespace Content.Server.GameObjects.Components.Body
ContainedMechanism = data; ContainedMechanism = data;
Owner.Name = Loc.GetString(ContainedMechanism.Name); Owner.Name = Loc.GetString(ContainedMechanism.Name);
if (Owner.TryGetComponent(out SpriteComponent component)) if (Owner.TryGetComponent(out SpriteComponent? component))
{ {
component.LayerSetRSI(0, data.RSIPath); component.LayerSetRSI(0, data.RSIPath);
component.LayerSetState(0, data.RSIState); component.LayerSetState(0, data.RSIState);
@@ -111,7 +111,7 @@ namespace Content.Server.GameObjects.Components.Body
if (serializer.Reading && debugLoadMechanismData != "") if (serializer.Reading && debugLoadMechanismData != "")
{ {
_prototypeManager.TryIndex(debugLoadMechanismData, out MechanismPrototype data); _prototypeManager.TryIndex(debugLoadMechanismData!, out MechanismPrototype data);
var mechanism = new Mechanism(data); var mechanism = new Mechanism(data);
mechanism.EnsureInitialize(); mechanism.EnsureInitialize();
@@ -155,7 +155,18 @@ namespace Content.Server.GameObjects.Components.Body
/// </summary> /// </summary>
private void HandleReceiveBodyPart(int key) private void HandleReceiveBodyPart(int key)
{ {
CloseSurgeryUI(_performerCache.GetComponent<BasicActorComponent>().playerSession); if (_performerCache == null ||
!_performerCache.TryGetComponent(out IActorComponent? actor))
{
return;
}
CloseSurgeryUI(actor.playerSession);
if (_bodyManagerComponentCache == null)
{
return;
}
// TODO: sanity checks to see whether user is in range, user is still able-bodied, target is still the same, etc etc // TODO: sanity checks to see whether user is in range, user is still able-bodied, target is still the same, etc etc
if (!_optionsCache.TryGetValue(key, out var targetObject)) if (!_optionsCache.TryGetValue(key, out var targetObject))
@@ -165,36 +176,37 @@ namespace Content.Server.GameObjects.Components.Body
return; return;
} }
var target = targetObject as BodyPart; var target = (BodyPart) targetObject;
var message = target.TryInstallDroppedMechanism(this)
? Loc.GetString("You jam the {0} inside {1:them}.", ContainedMechanism.Name, _performerCache)
: Loc.GetString("You can't fit it in!");
_sharedNotifyManager.PopupMessage( _sharedNotifyManager.PopupMessage(
_bodyManagerComponentCache.Owner, _bodyManagerComponentCache.Owner,
_performerCache, _performerCache,
!target.TryInstallDroppedMechanism(this) message);
? Loc.GetString("You can't fit it in!")
: Loc.GetString("You jam the {1} inside {0:them}.", _performerCache, ContainedMechanism.Name));
// TODO: {1:theName} // TODO: {1:theName}
} }
private void OpenSurgeryUI(IPlayerSession session) private void OpenSurgeryUI(IPlayerSession session)
{ {
_userInterface.Open(session); UserInterface?.Open(session);
} }
private void UpdateSurgeryUIBodyPartRequest(IPlayerSession session, Dictionary<string, int> options) private void UpdateSurgeryUIBodyPartRequest(IPlayerSession session, Dictionary<string, int> options)
{ {
_userInterface.SendMessage(new RequestBodyPartSurgeryUIMessage(options), session); UserInterface?.SendMessage(new RequestBodyPartSurgeryUIMessage(options), session);
} }
private void CloseSurgeryUI(IPlayerSession session) private void CloseSurgeryUI(IPlayerSession session)
{ {
_userInterface.Close(session); UserInterface?.Close(session);
} }
private void CloseAllSurgeryUIs() private void CloseAllSurgeryUIs()
{ {
_userInterface.CloseAll(); UserInterface?.CloseAll();
} }
private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage message) private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage message)

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.Body; using Content.Server.Body;
using Content.Server.Body.Mechanisms; using Content.Server.Body.Mechanisms;
@@ -18,6 +19,8 @@ using Robust.Shared.IoC;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Log; using Robust.Shared.Log;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Body namespace Content.Server.GameObjects.Components.Body
{ {
@@ -30,9 +33,7 @@ namespace Content.Server.GameObjects.Components.Body
[RegisterComponent] [RegisterComponent]
public class SurgeryToolComponent : Component, ISurgeon, IAfterInteract public class SurgeryToolComponent : Component, ISurgeon, IAfterInteract
{ {
#pragma warning disable 649 [Dependency] private readonly ISharedNotifyManager _sharedNotifyManager = default!;
[Dependency] private readonly ISharedNotifyManager _sharedNotifyManager;
#pragma warning restore 649
public override string Name => "SurgeryTool"; public override string Name => "SurgeryTool";
public override uint? NetID => ContentNetIDs.SURGERY; public override uint? NetID => ContentNetIDs.SURGERY;
@@ -41,17 +42,22 @@ namespace Content.Server.GameObjects.Components.Body
private float _baseOperateTime; private float _baseOperateTime;
private BodyManagerComponent _bodyManagerComponentCache; private BodyManagerComponent? _bodyManagerComponentCache;
private ISurgeon.MechanismRequestCallback _callbackCache; private ISurgeon.MechanismRequestCallback? _callbackCache;
private int _idHash; private int _idHash;
private IEntity _performerCache; private IEntity? _performerCache;
private SurgeryType _surgeryType; private SurgeryType _surgeryType;
private BoundUserInterface _userInterface; [ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(GenericSurgeryUiKey.Key, out var boundUi)
? boundUi
: null;
void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
{ {
@@ -60,7 +66,7 @@ namespace Content.Server.GameObjects.Components.Body
return; return;
} }
if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) if (!eventArgs.User.TryGetComponent(out IActorComponent? actor))
{ {
return; return;
} }
@@ -73,7 +79,7 @@ namespace Content.Server.GameObjects.Components.Body
_callbackCache = null; _callbackCache = null;
// Attempt surgery on a BodyManagerComponent by sending a list of operable BodyParts to the client to choose from // Attempt surgery on a BodyManagerComponent by sending a list of operable BodyParts to the client to choose from
if (eventArgs.Target.TryGetComponent(out BodyManagerComponent body)) if (eventArgs.Target.TryGetComponent(out BodyManagerComponent? body))
{ {
// Create dictionary to send to client (text to be shown : data sent back if selected) // Create dictionary to send to client (text to be shown : data sent back if selected)
var toSend = new Dictionary<string, int>(); var toSend = new Dictionary<string, int>();
@@ -105,13 +111,7 @@ namespace Content.Server.GameObjects.Components.Body
// Attempt surgery on a DroppedBodyPart - there's only one possible target so no need for selection UI // Attempt surgery on a DroppedBodyPart - there's only one possible target so no need for selection UI
_performerCache = eventArgs.User; _performerCache = eventArgs.User;
if (droppedBodyPart.ContainedBodyPart == null) DebugTools.AssertNotNull(droppedBodyPart.ContainedBodyPart);
{
// Throw error if the DroppedBodyPart has no data in it.
Logger.Debug(
"Surgery was attempted on an IEntity with a DroppedBodyPartComponent that doesn't have a BodyPart in it!");
throw new InvalidOperationException("A DroppedBodyPartComponent exists without a BodyPart in it!");
}
// If surgery can be performed... // If surgery can be performed...
if (!droppedBodyPart.ContainedBodyPart.SurgeryCheck(_surgeryType)) if (!droppedBodyPart.ContainedBodyPart.SurgeryCheck(_surgeryType))
@@ -144,7 +144,7 @@ namespace Content.Server.GameObjects.Components.Body
toSend.Add(mechanism.Name, _idHash++); toSend.Add(mechanism.Name, _idHash++);
} }
if (_optionsCache.Count > 0) if (_optionsCache.Count > 0 && _performerCache != null)
{ {
OpenSurgeryUI(_performerCache.GetComponent<BasicActorComponent>().playerSession); OpenSurgeryUI(_performerCache.GetComponent<BasicActorComponent>().playerSession);
UpdateSurgeryUIMechanismRequest(_performerCache.GetComponent<BasicActorComponent>().playerSession, UpdateSurgeryUIMechanismRequest(_performerCache.GetComponent<BasicActorComponent>().playerSession,
@@ -162,34 +162,35 @@ namespace Content.Server.GameObjects.Components.Body
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>() if (UserInterface != null)
.GetBoundUserInterface(GenericSurgeryUiKey.Key); {
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
}
} }
private void OpenSurgeryUI(IPlayerSession session) private void OpenSurgeryUI(IPlayerSession session)
{ {
_userInterface.Open(session); UserInterface?.Open(session);
} }
private void UpdateSurgeryUIBodyPartRequest(IPlayerSession session, Dictionary<string, int> options) private void UpdateSurgeryUIBodyPartRequest(IPlayerSession session, Dictionary<string, int> options)
{ {
_userInterface.SendMessage(new RequestBodyPartSurgeryUIMessage(options), session); UserInterface?.SendMessage(new RequestBodyPartSurgeryUIMessage(options), session);
} }
private void UpdateSurgeryUIMechanismRequest(IPlayerSession session, Dictionary<string, int> options) private void UpdateSurgeryUIMechanismRequest(IPlayerSession session, Dictionary<string, int> options)
{ {
_userInterface.SendMessage(new RequestMechanismSurgeryUIMessage(options), session); UserInterface?.SendMessage(new RequestMechanismSurgeryUIMessage(options), session);
} }
private void CloseSurgeryUI(IPlayerSession session) private void CloseSurgeryUI(IPlayerSession session)
{ {
_userInterface.Close(session); UserInterface?.Close(session);
} }
private void CloseAllSurgeryUIs() private void CloseAllSurgeryUIs()
{ {
_userInterface.CloseAll(); UserInterface?.CloseAll();
} }
private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage message) private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage message)
@@ -211,14 +212,22 @@ namespace Content.Server.GameObjects.Components.Body
/// </summary> /// </summary>
private void HandleReceiveBodyPart(int key) private void HandleReceiveBodyPart(int key)
{ {
CloseSurgeryUI(_performerCache.GetComponent<BasicActorComponent>().playerSession); if (_performerCache == null ||
// TODO: sanity checks to see whether user is in range, user is still able-bodied, target is still the same, etc etc !_performerCache.TryGetComponent(out IActorComponent? actor))
if (!_optionsCache.TryGetValue(key, out var targetObject))
{ {
SendNoUsefulWayToUseAnymorePopup(); return;
} }
var target = targetObject as BodyPart; CloseSurgeryUI(actor.playerSession);
// TODO: sanity checks to see whether user is in range, user is still able-bodied, target is still the same, etc etc
if (!_optionsCache.TryGetValue(key, out var targetObject) ||
_bodyManagerComponentCache == null)
{
SendNoUsefulWayToUseAnymorePopup();
return;
}
var target = (BodyPart) targetObject!;
if (!target.AttemptSurgery(_surgeryType, _bodyManagerComponentCache, this, _performerCache)) if (!target.AttemptSurgery(_surgeryType, _bodyManagerComponentCache, this, _performerCache))
{ {
@@ -233,19 +242,27 @@ namespace Content.Server.GameObjects.Components.Body
private void HandleReceiveMechanism(int key) private void HandleReceiveMechanism(int key)
{ {
// TODO: sanity checks to see whether user is in range, user is still able-bodied, target is still the same, etc etc // TODO: sanity checks to see whether user is in range, user is still able-bodied, target is still the same, etc etc
if (!_optionsCache.TryGetValue(key, out var targetObject)) if (!_optionsCache.TryGetValue(key, out var targetObject) ||
_performerCache == null ||
!_performerCache.TryGetComponent(out IActorComponent? actor))
{ {
SendNoUsefulWayToUseAnymorePopup(); SendNoUsefulWayToUseAnymorePopup();
return;
} }
var target = targetObject as Mechanism; var target = targetObject as Mechanism;
CloseSurgeryUI(_performerCache.GetComponent<BasicActorComponent>().playerSession); CloseSurgeryUI(actor.playerSession);
_callbackCache(target, _bodyManagerComponentCache, this, _performerCache); _callbackCache?.Invoke(target, _bodyManagerComponentCache, this, _performerCache);
} }
private void SendNoUsefulWayToUsePopup() private void SendNoUsefulWayToUsePopup()
{ {
if (_bodyManagerComponentCache == null)
{
return;
}
_sharedNotifyManager.PopupMessage( _sharedNotifyManager.PopupMessage(
_bodyManagerComponentCache.Owner, _bodyManagerComponentCache.Owner,
_performerCache, _performerCache,
@@ -254,6 +271,11 @@ namespace Content.Server.GameObjects.Components.Body
private void SendNoUsefulWayToUseAnymorePopup() private void SendNoUsefulWayToUseAnymorePopup()
{ {
if (_bodyManagerComponentCache == null)
{
return;
}
_sharedNotifyManager.PopupMessage( _sharedNotifyManager.PopupMessage(
_bodyManagerComponentCache.Owner, _bodyManagerComponentCache.Owner,
_performerCache, _performerCache,

View File

@@ -34,13 +34,11 @@ namespace Content.Server.GameObjects.Components.Buckle
[RegisterComponent] [RegisterComponent]
public class BuckleComponent : SharedBuckleComponent, IInteractHand, IDragDrop public class BuckleComponent : SharedBuckleComponent, IInteractHand, IDragDrop
{ {
#pragma warning disable 649
[Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IEntitySystemManager _entitySystem = default!; [Dependency] private readonly IEntitySystemManager _entitySystem = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IServerNotifyManager _notifyManager = default!; [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
[Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IMapManager _mapManager = default!;
#pragma warning restore 649
private int _size; private int _size;

View File

@@ -10,6 +10,7 @@ using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems; using Robust.Shared.GameObjects.Systems;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
@@ -19,21 +20,11 @@ namespace Content.Server.GameObjects.Components.Cargo
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
public class CargoConsoleComponent : SharedCargoConsoleComponent, IActivate public class CargoConsoleComponent : SharedCargoConsoleComponent, IActivate
{ {
#pragma warning disable 649
[Dependency] private readonly ICargoOrderDataManager _cargoOrderDataManager = default!; [Dependency] private readonly ICargoOrderDataManager _cargoOrderDataManager = default!;
#pragma warning restore 649
[ViewVariables] [ViewVariables]
public int Points = 1000; public int Points = 1000;
private BoundUserInterface _userInterface = default!;
[ViewVariables]
public GalacticMarketComponent Market { get; private set; } = default!;
[ViewVariables]
public CargoOrderDatabaseComponent Orders { get; private set; } = default!;
private CargoBankAccount? _bankAccount; private CargoBankAccount? _bankAccount;
[ViewVariables] [ViewVariables]
@@ -65,22 +56,49 @@ namespace Content.Server.GameObjects.Components.Cargo
private bool _requestOnly = false; private bool _requestOnly = false;
private PowerReceiverComponent _powerReceiver = default!; private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
private bool Powered => _powerReceiver.Powered;
private CargoConsoleSystem _cargoConsoleSystem = default!; private CargoConsoleSystem _cargoConsoleSystem = default!;
[ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(CargoConsoleUiKey.Key, out var boundUi)
? boundUi
: null;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
Market = Owner.GetComponent<GalacticMarketComponent>();
Orders = Owner.GetComponent<CargoOrderDatabaseComponent>(); if (!Owner.EnsureComponent(out GalacticMarketComponent _))
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(CargoConsoleUiKey.Key); {
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; Logger.Warning($"Entity {Owner} at {Owner.Transform.MapPosition} had no {nameof(GalacticMarketComponent)}");
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>(); }
if (!Owner.EnsureComponent(out CargoOrderDatabaseComponent _))
{
Logger.Warning($"Entity {Owner} at {Owner.Transform.MapPosition} had no {nameof(GalacticMarketComponent)}");
}
if (UserInterface != null)
{
UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
}
_cargoConsoleSystem = EntitySystem.Get<CargoConsoleSystem>(); _cargoConsoleSystem = EntitySystem.Get<CargoConsoleSystem>();
BankAccount = _cargoConsoleSystem.StationAccount; BankAccount = _cargoConsoleSystem.StationAccount;
} }
public override void OnRemove()
{
if (UserInterface != null)
{
UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
}
base.OnRemove();
}
/// <summary> /// <summary>
/// Reads data from YAML /// Reads data from YAML
/// </summary> /// </summary>
@@ -93,8 +111,13 @@ namespace Content.Server.GameObjects.Components.Cargo
private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg) private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg)
{ {
if (!Owner.TryGetComponent(out CargoOrderDatabaseComponent? orders))
{
return;
}
var message = serverMsg.Message; var message = serverMsg.Message;
if (!Orders.ConnectedToDatabase) if (!orders.ConnectedToDatabase)
return; return;
if (!Powered) if (!Powered)
return; return;
@@ -107,39 +130,39 @@ namespace Content.Server.GameObjects.Components.Cargo
break; break;
} }
_cargoOrderDataManager.AddOrder(Orders.Database.Id, msg.Requester, msg.Reason, msg.ProductId, msg.Amount, _bankAccount.Id); _cargoOrderDataManager.AddOrder(orders.Database.Id, msg.Requester, msg.Reason, msg.ProductId, msg.Amount, _bankAccount.Id);
break; break;
} }
case CargoConsoleRemoveOrderMessage msg: case CargoConsoleRemoveOrderMessage msg:
{ {
_cargoOrderDataManager.RemoveOrder(Orders.Database.Id, msg.OrderNumber); _cargoOrderDataManager.RemoveOrder(orders.Database.Id, msg.OrderNumber);
break; break;
} }
case CargoConsoleApproveOrderMessage msg: case CargoConsoleApproveOrderMessage msg:
{ {
if (_requestOnly || if (_requestOnly ||
!Orders.Database.TryGetOrder(msg.OrderNumber, out var order) || !orders.Database.TryGetOrder(msg.OrderNumber, out var order) ||
_bankAccount == null) _bankAccount == null)
{ {
break; break;
} }
_prototypeManager.TryIndex(order.ProductId, out CargoProductPrototype product); _prototypeManager.TryIndex(order.ProductId, out CargoProductPrototype product);
if (product == null) if (product == null!)
break; break;
var capacity = _cargoOrderDataManager.GetCapacity(Orders.Database.Id); var capacity = _cargoOrderDataManager.GetCapacity(orders.Database.Id);
if (capacity.CurrentCapacity == capacity.MaxCapacity) if (capacity.CurrentCapacity == capacity.MaxCapacity)
break; break;
if (!_cargoConsoleSystem.ChangeBalance(_bankAccount.Id, (-product.PointCost) * order.Amount)) if (!_cargoConsoleSystem.ChangeBalance(_bankAccount.Id, (-product.PointCost) * order.Amount))
break; break;
_cargoOrderDataManager.ApproveOrder(Orders.Database.Id, msg.OrderNumber); _cargoOrderDataManager.ApproveOrder(orders.Database.Id, msg.OrderNumber);
UpdateUIState(); UpdateUIState();
break; break;
} }
case CargoConsoleShuttleMessage _: case CargoConsoleShuttleMessage _:
{ {
var approvedOrders = _cargoOrderDataManager.RemoveAndGetApprovedFrom(Orders.Database); var approvedOrders = _cargoOrderDataManager.RemoveAndGetApprovedFrom(orders.Database);
Orders.Database.ClearOrderCapacity(); orders.Database.ClearOrderCapacity();
// TODO replace with shuttle code // TODO replace with shuttle code
// TEMPORARY loop for spawning stuff on top of console // TEMPORARY loop for spawning stuff on top of console
@@ -166,12 +189,12 @@ namespace Content.Server.GameObjects.Components.Cargo
if (!Powered) if (!Powered)
return; return;
_userInterface.Open(actor.playerSession); UserInterface?.Open(actor.playerSession);
} }
private void UpdateUIState() private void UpdateUIState()
{ {
if (_bankAccount == null) if (_bankAccount == null || !Owner.IsValid())
{ {
return; return;
} }
@@ -180,7 +203,7 @@ namespace Content.Server.GameObjects.Components.Cargo
var name = _bankAccount.Name; var name = _bankAccount.Name;
var balance = _bankAccount.Balance; var balance = _bankAccount.Balance;
var capacity = _cargoOrderDataManager.GetCapacity(id); var capacity = _cargoOrderDataManager.GetCapacity(id);
_userInterface.SetState(new CargoConsoleInterfaceState(_requestOnly, id, name, balance, capacity)); UserInterface?.SetState(new CargoConsoleInterfaceState(_requestOnly, id, name, balance, capacity));
} }
} }
} }

View File

@@ -1,4 +1,6 @@
using System; #nullable enable
using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Content.Server.GameObjects.Components.GUI; using Content.Server.GameObjects.Components.GUI;
@@ -40,24 +42,26 @@ namespace Content.Server.GameObjects.Components.Chemistry
[ComponentReference(typeof(IInteractUsing))] [ComponentReference(typeof(IInteractUsing))]
public class ChemMasterComponent : SharedChemMasterComponent, IActivate, IInteractUsing, ISolutionChange public class ChemMasterComponent : SharedChemMasterComponent, IActivate, IInteractUsing, ISolutionChange
{ {
#pragma warning disable 649 [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
[Dependency] private readonly IServerNotifyManager _notifyManager; [Dependency] private readonly ILocalizationManager _localizationManager = default!;
[Dependency] private readonly ILocalizationManager _localizationManager;
#pragma warning restore 649
[ViewVariables] private BoundUserInterface _userInterface; [ViewVariables] private ContainerSlot _beakerContainer = default!;
[ViewVariables] private ContainerSlot _beakerContainer; [ViewVariables] private string _packPrototypeId = "";
[ViewVariables] private string _packPrototypeId;
[ViewVariables] private bool HasBeaker => _beakerContainer.ContainedEntity != null; [ViewVariables] private bool HasBeaker => _beakerContainer.ContainedEntity != null;
[ViewVariables] private bool BufferModeTransfer = true; [ViewVariables] private bool _bufferModeTransfer = true;
private PowerReceiverComponent _powerReceiver; private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
private bool Powered => _powerReceiver.Powered;
private readonly SolutionComponent BufferSolution = new SolutionComponent(); private readonly SolutionComponent BufferSolution = new SolutionComponent();
[ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(ChemMasterUiKey.Key, out var boundUi)
? boundUi
: null;
/// <summary> /// <summary>
/// Shows the serializer how to save/load this components yaml prototype. /// Shows the serializer how to save/load this components yaml prototype.
@@ -77,14 +81,19 @@ namespace Content.Server.GameObjects.Components.Chemistry
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(ChemMasterUiKey.Key); if (UserInterface != null)
_userInterface.OnReceiveMessage += OnUiReceiveMessage; {
UserInterface.OnReceiveMessage += OnUiReceiveMessage;
}
_beakerContainer = _beakerContainer =
ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-reagentContainerContainer", Owner); ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-reagentContainerContainer", Owner);
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
_powerReceiver.OnPowerStateChanged += OnPowerChanged; if (Owner.TryGetComponent(out PowerReceiverComponent? receiver))
{
receiver.OnPowerStateChanged += OnPowerChanged;
}
//BufferSolution = Owner.BufferSolution //BufferSolution = Owner.BufferSolution
BufferSolution.Solution = new Solution(); BufferSolution.Solution = new Solution();
@@ -93,7 +102,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
UpdateUserInterface(); UpdateUserInterface();
} }
private void OnPowerChanged(object sender, PowerStateEventArgs e) private void OnPowerChanged(object? sender, PowerStateEventArgs e)
{ {
UpdateUserInterface(); UpdateUserInterface();
} }
@@ -105,6 +114,11 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// <param name="obj">A user interface message from the client.</param> /// <param name="obj">A user interface message from the client.</param>
private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj) private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj)
{ {
if (obj.Session.AttachedEntity == null)
{
return;
}
var msg = (UiActionMessage) obj.Message; var msg = (UiActionMessage) obj.Message;
var needsPower = msg.action switch var needsPower = msg.action switch
{ {
@@ -124,11 +138,11 @@ namespace Content.Server.GameObjects.Components.Chemistry
TransferReagent(msg.id, msg.amount, msg.isBuffer); TransferReagent(msg.id, msg.amount, msg.isBuffer);
break; break;
case UiAction.Transfer: case UiAction.Transfer:
BufferModeTransfer = true; _bufferModeTransfer = true;
UpdateUserInterface(); UpdateUserInterface();
break; break;
case UiAction.Discard: case UiAction.Discard:
BufferModeTransfer = false; _bufferModeTransfer = false;
UpdateUserInterface(); UpdateUserInterface();
break; break;
case UiAction.CreatePills: case UiAction.CreatePills:
@@ -147,7 +161,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// </summary> /// </summary>
/// <param name="playerEntity">The player entity.</param> /// <param name="playerEntity">The player entity.</param>
/// <returns>Returns true if the entity can use the chem master, and false if it cannot.</returns> /// <returns>Returns true if the entity can use the chem master, and false if it cannot.</returns>
private bool PlayerCanUseChemMaster(IEntity playerEntity, bool needsPower = true) private bool PlayerCanUseChemMaster(IEntity? playerEntity, bool needsPower = true)
{ {
//Need player entity to check if they are still able to use the chem master //Need player entity to check if they are still able to use the chem master
if (playerEntity == null) if (playerEntity == null)
@@ -172,18 +186,18 @@ namespace Content.Server.GameObjects.Components.Chemistry
if (beaker == null) if (beaker == null)
{ {
return new ChemMasterBoundUserInterfaceState(Powered, false, ReagentUnit.New(0), ReagentUnit.New(0), return new ChemMasterBoundUserInterfaceState(Powered, false, ReagentUnit.New(0), ReagentUnit.New(0),
"", Owner.Name, null, BufferSolution.ReagentList.ToList(), BufferModeTransfer, BufferSolution.CurrentVolume, BufferSolution.MaxVolume); "", Owner.Name, new List<Solution.ReagentQuantity>(), BufferSolution.ReagentList.ToList(), _bufferModeTransfer, BufferSolution.CurrentVolume, BufferSolution.MaxVolume);
} }
var solution = beaker.GetComponent<SolutionComponent>(); var solution = beaker.GetComponent<SolutionComponent>();
return new ChemMasterBoundUserInterfaceState(Powered, true, solution.CurrentVolume, solution.MaxVolume, return new ChemMasterBoundUserInterfaceState(Powered, true, solution.CurrentVolume, solution.MaxVolume,
beaker.Name, Owner.Name, solution.ReagentList.ToList(), BufferSolution.ReagentList.ToList(), BufferModeTransfer, BufferSolution.CurrentVolume, BufferSolution.MaxVolume); beaker.Name, Owner.Name, solution.ReagentList.ToList(), BufferSolution.ReagentList.ToList(), _bufferModeTransfer, BufferSolution.CurrentVolume, BufferSolution.MaxVolume);
} }
private void UpdateUserInterface() private void UpdateUserInterface()
{ {
var state = GetUserInterfaceState(); var state = GetUserInterfaceState();
_userInterface.SetState(state); UserInterface?.SetState(state);
} }
/// <summary> /// <summary>
@@ -207,7 +221,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
private void TransferReagent(string id, ReagentUnit amount, bool isBuffer) private void TransferReagent(string id, ReagentUnit amount, bool isBuffer)
{ {
if (!HasBeaker && BufferModeTransfer) return; if (!HasBeaker && _bufferModeTransfer) return;
var beaker = _beakerContainer.ContainedEntity; var beaker = _beakerContainer.ContainedEntity;
var beakerSolution = beaker.GetComponent<SolutionComponent>(); var beakerSolution = beaker.GetComponent<SolutionComponent>();
if (isBuffer) if (isBuffer)
@@ -227,7 +241,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
} }
BufferSolution.Solution.RemoveReagent(id, actualAmount); BufferSolution.Solution.RemoveReagent(id, actualAmount);
if (BufferModeTransfer) if (_bufferModeTransfer)
{ {
beakerSolution.Solution.AddReagent(id, actualAmount); beakerSolution.Solution.AddReagent(id, actualAmount);
} }
@@ -351,12 +365,12 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// <param name="args">Data relevant to the event such as the actor which triggered it.</param> /// <param name="args">Data relevant to the event such as the actor which triggered it.</param>
void IActivate.Activate(ActivateEventArgs args) void IActivate.Activate(ActivateEventArgs args)
{ {
if (!args.User.TryGetComponent(out IActorComponent actor)) if (!args.User.TryGetComponent(out IActorComponent? actor))
{ {
return; return;
} }
if (!args.User.TryGetComponent(out IHandsComponent hands)) if (!args.User.TryGetComponent(out IHandsComponent? hands))
{ {
_notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User, _notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User,
_localizationManager.GetString("You have no hands.")); _localizationManager.GetString("You have no hands."));
@@ -366,7 +380,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
var activeHandEntity = hands.GetActiveHand?.Owner; var activeHandEntity = hands.GetActiveHand?.Owner;
if (activeHandEntity == null) if (activeHandEntity == null)
{ {
_userInterface.Open(actor.playerSession); UserInterface?.Open(actor.playerSession);
} }
} }
@@ -379,13 +393,20 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// <returns></returns> /// <returns></returns>
async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs args) async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs args)
{ {
if (!args.User.TryGetComponent(out IHandsComponent hands)) if (!args.User.TryGetComponent(out IHandsComponent? hands))
{ {
_notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User, _notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User,
_localizationManager.GetString("You have no hands.")); _localizationManager.GetString("You have no hands."));
return true; return true;
} }
if (hands.GetActiveHand == null)
{
_notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User,
Loc.GetString("You have nothing on your hand."));
return false;
}
var activeHandEntity = hands.GetActiveHand.Owner; var activeHandEntity = hands.GetActiveHand.Owner;
if (activeHandEntity.TryGetComponent<SolutionComponent>(out var solution)) if (activeHandEntity.TryGetComponent<SolutionComponent>(out var solution))
{ {

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using Content.Server.GameObjects.Components.Body.Circulatory; using Content.Server.GameObjects.Components.Body.Circulatory;
using Content.Server.Interfaces; using Content.Server.Interfaces;
using Content.Server.Utility; using Content.Server.Utility;
@@ -22,9 +23,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
[RegisterComponent] [RegisterComponent]
public class InjectorComponent : SharedInjectorComponent, IAfterInteract, IUse public class InjectorComponent : SharedInjectorComponent, IAfterInteract, IUse
{ {
#pragma warning disable 649 [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
[Dependency] private readonly IServerNotifyManager _notifyManager;
#pragma warning restore 649
/// <summary> /// <summary>
/// Whether or not the injector is able to draw from containers or if it's a single use /// Whether or not the injector is able to draw from containers or if it's a single use
@@ -53,11 +52,6 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// </summary> /// </summary>
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
private InjectorToggleMode _toggleState; private InjectorToggleMode _toggleState;
/// <summary>
/// Internal solution container
/// </summary>
[ViewVariables]
private SolutionComponent _internalContents;
public override void ExposeData(ObjectSerializer serializer) public override void ExposeData(ObjectSerializer serializer)
{ {
@@ -69,9 +63,15 @@ namespace Content.Server.GameObjects.Components.Chemistry
protected override void Startup() protected override void Startup()
{ {
base.Startup(); base.Startup();
_internalContents = Owner.GetComponent<SolutionComponent>();
_internalContents.Capabilities |= SolutionCaps.Injector; Owner.EnsureComponent<SolutionComponent>();
//Set _toggleState based on prototype
if (Owner.TryGetComponent(out SolutionComponent? solution))
{
solution.Capabilities |= SolutionCaps.Injector;
}
// Set _toggleState based on prototype
_toggleState = _injectOnly ? InjectorToggleMode.Inject : InjectorToggleMode.Draw; _toggleState = _injectOnly ? InjectorToggleMode.Inject : InjectorToggleMode.Draw;
} }
@@ -114,7 +114,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return; if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
//Make sure we have the attacking entity //Make sure we have the attacking entity
if (eventArgs.Target == null || !_internalContents.Injector) if (eventArgs.Target == null || !Owner.TryGetComponent(out SolutionComponent? solution) || !solution.Injector)
{ {
return; return;
} }
@@ -134,7 +134,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
} }
else //Handle injecting into bloodstream else //Handle injecting into bloodstream
{ {
if (targetEntity.TryGetComponent(out BloodstreamComponent bloodstream) && if (targetEntity.TryGetComponent(out BloodstreamComponent? bloodstream) &&
_toggleState == InjectorToggleMode.Inject) _toggleState == InjectorToggleMode.Inject)
{ {
TryInjectIntoBloodstream(bloodstream, eventArgs.User); TryInjectIntoBloodstream(bloodstream, eventArgs.User);
@@ -155,7 +155,8 @@ namespace Content.Server.GameObjects.Components.Chemistry
private void TryInjectIntoBloodstream(BloodstreamComponent targetBloodstream, IEntity user) private void TryInjectIntoBloodstream(BloodstreamComponent targetBloodstream, IEntity user)
{ {
if (_internalContents.CurrentVolume == 0) if (!Owner.TryGetComponent(out SolutionComponent? solution) ||
solution.CurrentVolume == 0)
{ {
return; return;
} }
@@ -170,7 +171,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
} }
//Move units from attackSolution to targetSolution //Move units from attackSolution to targetSolution
var removedSolution = _internalContents.SplitSolution(realTransferAmount); var removedSolution = solution.SplitSolution(realTransferAmount);
if (!targetBloodstream.TryTransferSolution(removedSolution)) if (!targetBloodstream.TryTransferSolution(removedSolution))
{ {
return; return;
@@ -183,7 +184,8 @@ namespace Content.Server.GameObjects.Components.Chemistry
private void TryInject(SolutionComponent targetSolution, IEntity user) private void TryInject(SolutionComponent targetSolution, IEntity user)
{ {
if (_internalContents.CurrentVolume == 0) if (!Owner.TryGetComponent(out SolutionComponent? solution) ||
solution.CurrentVolume == 0)
{ {
return; return;
} }
@@ -198,7 +200,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
} }
//Move units from attackSolution to targetSolution //Move units from attackSolution to targetSolution
var removedSolution = _internalContents.SplitSolution(realTransferAmount); var removedSolution = solution.SplitSolution(realTransferAmount);
if (!targetSolution.TryAddSolution(removedSolution)) if (!targetSolution.TryAddSolution(removedSolution))
{ {
return; return;
@@ -211,7 +213,8 @@ namespace Content.Server.GameObjects.Components.Chemistry
private void TryDraw(SolutionComponent targetSolution, IEntity user) private void TryDraw(SolutionComponent targetSolution, IEntity user)
{ {
if (_internalContents.EmptyVolume == 0) if (!Owner.TryGetComponent(out SolutionComponent? solution) ||
solution.EmptyVolume == 0)
{ {
return; return;
} }
@@ -227,7 +230,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
//Move units from attackSolution to targetSolution //Move units from attackSolution to targetSolution
var removedSolution = targetSolution.SplitSolution(realTransferAmount); var removedSolution = targetSolution.SplitSolution(realTransferAmount);
if (!_internalContents.TryAddSolution(removedSolution)) if (!solution.TryAddSolution(removedSolution))
{ {
return; return;
} }
@@ -239,7 +242,12 @@ namespace Content.Server.GameObjects.Components.Chemistry
public override ComponentState GetComponentState() public override ComponentState GetComponentState()
{ {
return new InjectorComponentState(_internalContents.CurrentVolume, _internalContents.MaxVolume, _toggleState); Owner.TryGetComponent(out SolutionComponent? solution);
var currentVolume = solution?.CurrentVolume ?? ReagentUnit.Zero;
var maxVolume = solution?.MaxVolume ?? ReagentUnit.Zero;
return new InjectorComponentState(currentVolume, maxVolume, _toggleState);
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Content.Server.GameObjects.Components.GUI; using Content.Server.GameObjects.Components.GUI;
@@ -38,14 +39,11 @@ namespace Content.Server.GameObjects.Components.Chemistry
[ComponentReference(typeof(IInteractUsing))] [ComponentReference(typeof(IInteractUsing))]
public class ReagentDispenserComponent : SharedReagentDispenserComponent, IActivate, IInteractUsing, ISolutionChange public class ReagentDispenserComponent : SharedReagentDispenserComponent, IActivate, IInteractUsing, ISolutionChange
{ {
#pragma warning disable 649 [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
[Dependency] private readonly IServerNotifyManager _notifyManager; [Dependency] private readonly ILocalizationManager _localizationManager = default!;
[Dependency] private readonly ILocalizationManager _localizationManager;
#pragma warning restore 649
[ViewVariables] private BoundUserInterface _userInterface; [ViewVariables] private ContainerSlot _beakerContainer = default!;
[ViewVariables] private ContainerSlot _beakerContainer; [ViewVariables] private string _packPrototypeId = "";
[ViewVariables] private string _packPrototypeId;
[ViewVariables] private bool HasBeaker => _beakerContainer.ContainedEntity != null; [ViewVariables] private bool HasBeaker => _beakerContainer.ContainedEntity != null;
[ViewVariables] private ReagentUnit _dispenseAmount = ReagentUnit.New(10); [ViewVariables] private ReagentUnit _dispenseAmount = ReagentUnit.New(10);
@@ -53,9 +51,14 @@ namespace Content.Server.GameObjects.Components.Chemistry
[ViewVariables] [ViewVariables]
private SolutionComponent Solution => _beakerContainer.ContainedEntity.GetComponent<SolutionComponent>(); private SolutionComponent Solution => _beakerContainer.ContainedEntity.GetComponent<SolutionComponent>();
private PowerReceiverComponent _powerReceiver; private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
private bool Powered => _powerReceiver.Powered;
[ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(ReagentDispenserUiKey.Key, out var boundUi)
? boundUi
: null;
/// <summary> /// <summary>
/// Shows the serializer how to save/load this components yaml prototype. /// Shows the serializer how to save/load this components yaml prototype.
@@ -75,14 +78,19 @@ namespace Content.Server.GameObjects.Components.Chemistry
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(ReagentDispenserUiKey.Key); if (UserInterface != null)
_userInterface.OnReceiveMessage += OnUiReceiveMessage; {
UserInterface.OnReceiveMessage += OnUiReceiveMessage;
}
_beakerContainer = _beakerContainer =
ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-reagentContainerContainer", Owner); ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-reagentContainerContainer", Owner);
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
_powerReceiver.OnPowerStateChanged += OnPowerChanged; if (Owner.TryGetComponent(out PowerReceiverComponent? receiver))
{
receiver.OnPowerStateChanged += OnPowerChanged;
}
InitializeFromPrototype(); InitializeFromPrototype();
UpdateUserInterface(); UpdateUserInterface();
@@ -108,7 +116,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
} }
} }
private void OnPowerChanged(object sender, PowerStateEventArgs e) private void OnPowerChanged(object? sender, PowerStateEventArgs e)
{ {
UpdateUserInterface(); UpdateUserInterface();
} }
@@ -120,6 +128,11 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// <param name="obj">A user interface message from the client.</param> /// <param name="obj">A user interface message from the client.</param>
private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj) private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj)
{ {
if (obj.Session.AttachedEntity == null)
{
return;
}
var msg = (UiButtonPressedMessage) obj.Message; var msg = (UiButtonPressedMessage) obj.Message;
var needsPower = msg.Button switch var needsPower = msg.Button switch
{ {
@@ -175,7 +188,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// </summary> /// </summary>
/// <param name="playerEntity">The player entity.</param> /// <param name="playerEntity">The player entity.</param>
/// <returns>Returns true if the entity can use the dispenser, and false if it cannot.</returns> /// <returns>Returns true if the entity can use the dispenser, and false if it cannot.</returns>
private bool PlayerCanUseDispenser(IEntity playerEntity, bool needsPower = true) private bool PlayerCanUseDispenser(IEntity? playerEntity, bool needsPower = true)
{ {
//Need player entity to check if they are still able to use the dispenser //Need player entity to check if they are still able to use the dispenser
if (playerEntity == null) if (playerEntity == null)
@@ -211,7 +224,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
private void UpdateUserInterface() private void UpdateUserInterface()
{ {
var state = GetUserInterfaceState(); var state = GetUserInterfaceState();
_userInterface.SetState(state); UserInterface?.SetState(state);
} }
/// <summary> /// <summary>
@@ -265,12 +278,12 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// <param name="args">Data relevant to the event such as the actor which triggered it.</param> /// <param name="args">Data relevant to the event such as the actor which triggered it.</param>
void IActivate.Activate(ActivateEventArgs args) void IActivate.Activate(ActivateEventArgs args)
{ {
if (!args.User.TryGetComponent(out IActorComponent actor)) if (!args.User.TryGetComponent(out IActorComponent? actor))
{ {
return; return;
} }
if (!args.User.TryGetComponent(out IHandsComponent hands)) if (!args.User.TryGetComponent(out IHandsComponent? hands))
{ {
_notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User, _notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User,
_localizationManager.GetString("You have no hands.")); _localizationManager.GetString("You have no hands."));
@@ -280,7 +293,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
var activeHandEntity = hands.GetActiveHand?.Owner; var activeHandEntity = hands.GetActiveHand?.Owner;
if (activeHandEntity == null) if (activeHandEntity == null)
{ {
_userInterface.Open(actor.playerSession); UserInterface?.Open(actor.playerSession);
} }
} }
@@ -293,13 +306,20 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// <returns></returns> /// <returns></returns>
async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs args) async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs args)
{ {
if (!args.User.TryGetComponent(out IHandsComponent hands)) if (!args.User.TryGetComponent(out IHandsComponent? hands))
{ {
_notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User, _notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User,
_localizationManager.GetString("You have no hands.")); _localizationManager.GetString("You have no hands."));
return true; return true;
} }
if (hands.GetActiveHand == null)
{
_notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User,
Loc.GetString("You have nothing on your hand."));
return false;
}
var activeHandEntity = hands.GetActiveHand.Owner; var activeHandEntity = hands.GetActiveHand.Owner;
if (activeHandEntity.TryGetComponent<SolutionComponent>(out var solution)) if (activeHandEntity.TryGetComponent<SolutionComponent>(out var solution))
{ {

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.EntitySystems; #nullable enable
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.Chemistry; using Content.Shared.Chemistry;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
@@ -11,28 +12,27 @@ namespace Content.Server.GameObjects.Components.Chemistry
[RegisterComponent] [RegisterComponent]
public class TransformableContainerComponent : Component, ISolutionChange public class TransformableContainerComponent : Component, ISolutionChange
{ {
#pragma warning disable 649 [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager;
#pragma warning restore 649
public override string Name => "TransformableContainer"; public override string Name => "TransformableContainer";
private bool _transformed = false; private SpriteSpecifier? _initialSprite;
public bool Transformed { get => _transformed; } private string _initialName = default!;
private string _initialDescription = default!;
private ReagentPrototype? _currentReagent;
private SpriteSpecifier _initialSprite; public bool Transformed { get; private set; }
private string _initialName;
private string _initialDescription;
private SpriteComponent _sprite;
private ReagentPrototype _currentReagent;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_sprite = Owner.GetComponent<SpriteComponent>(); if (Owner.TryGetComponent(out SpriteComponent? sprite) &&
_initialSprite = new SpriteSpecifier.Rsi(new ResourcePath(_sprite.BaseRSIPath), "icon"); sprite.BaseRSIPath != null)
{
_initialSprite = new SpriteSpecifier.Rsi(new ResourcePath(sprite.BaseRSIPath), "icon");
}
_initialName = Owner.Name; _initialName = Owner.Name;
_initialDescription = Owner.Description; _initialDescription = Owner.Description;
} }
@@ -40,14 +40,20 @@ namespace Content.Server.GameObjects.Components.Chemistry
protected override void Startup() protected override void Startup()
{ {
base.Startup(); base.Startup();
Owner.GetComponent<SolutionComponent>().Capabilities |= SolutionCaps.FitsInDispenser;; Owner.GetComponent<SolutionComponent>().Capabilities |= SolutionCaps.FitsInDispenser;
} }
public void CancelTransformation() public void CancelTransformation()
{ {
_currentReagent = null; _currentReagent = null;
_transformed = false; Transformed = false;
_sprite.LayerSetSprite(0, _initialSprite);
if (Owner.TryGetComponent(out SpriteComponent? sprite) &&
_initialSprite != null)
{
sprite.LayerSetSprite(0, _initialSprite);
}
Owner.Name = _initialName; Owner.Name = _initialName;
Owner.Description = _initialDescription; Owner.Description = _initialDescription;
} }
@@ -76,11 +82,16 @@ namespace Content.Server.GameObjects.Components.Chemistry
!string.IsNullOrWhiteSpace(proto.SpriteReplacementPath)) !string.IsNullOrWhiteSpace(proto.SpriteReplacementPath))
{ {
var spriteSpec = new SpriteSpecifier.Rsi(new ResourcePath("Objects/Drinks/" + proto.SpriteReplacementPath),"icon"); var spriteSpec = new SpriteSpecifier.Rsi(new ResourcePath("Objects/Drinks/" + proto.SpriteReplacementPath),"icon");
_sprite.LayerSetSprite(0, spriteSpec);
if (Owner.TryGetComponent(out SpriteComponent? sprite))
{
sprite?.LayerSetSprite(0, spriteSpec);
}
Owner.Name = proto.Name + " glass"; Owner.Name = proto.Name + " glass";
Owner.Description = proto.Description; Owner.Description = proto.Description;
_currentReagent = proto; _currentReagent = proto;
_transformed = true; Transformed = true;
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.Components.Power.ApcNetComponents; #nullable enable
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components.Command; using Content.Shared.GameObjects.Components.Command;
using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Interfaces.GameObjects.Components;
@@ -8,6 +9,7 @@ using Robust.Server.Interfaces.Player;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Command namespace Content.Server.GameObjects.Components.Command
{ {
@@ -15,22 +17,27 @@ namespace Content.Server.GameObjects.Components.Command
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
public class CommunicationsConsoleComponent : SharedCommunicationsConsoleComponent, IActivate public class CommunicationsConsoleComponent : SharedCommunicationsConsoleComponent, IActivate
{ {
#pragma warning disable 649 [Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
[Dependency] private IEntitySystemManager _entitySystemManager;
#pragma warning restore 649 private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
private BoundUserInterface _userInterface;
private PowerReceiverComponent _powerReceiver;
private bool Powered => _powerReceiver.Powered;
private RoundEndSystem RoundEndSystem => _entitySystemManager.GetEntitySystem<RoundEndSystem>(); private RoundEndSystem RoundEndSystem => _entitySystemManager.GetEntitySystem<RoundEndSystem>();
[ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(CommunicationsConsoleUiKey.Key, out var boundUi)
? boundUi
: null;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(CommunicationsConsoleUiKey.Key); if (UserInterface != null)
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; {
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>(); UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
}
RoundEndSystem.OnRoundEndCountdownStarted += UpdateBoundInterface; RoundEndSystem.OnRoundEndCountdownStarted += UpdateBoundInterface;
RoundEndSystem.OnRoundEndCountdownCancelled += UpdateBoundInterface; RoundEndSystem.OnRoundEndCountdownCancelled += UpdateBoundInterface;
@@ -39,7 +46,7 @@ namespace Content.Server.GameObjects.Components.Command
private void UpdateBoundInterface() private void UpdateBoundInterface()
{ {
_userInterface.SetState(new CommunicationsConsoleInterfaceState(RoundEndSystem.ExpectedCountdownEnd)); UserInterface?.SetState(new CommunicationsConsoleInterfaceState(RoundEndSystem.ExpectedCountdownEnd));
} }
private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage obj) private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage obj)
@@ -58,12 +65,12 @@ namespace Content.Server.GameObjects.Components.Command
public void OpenUserInterface(IPlayerSession session) public void OpenUserInterface(IPlayerSession session)
{ {
_userInterface.Open(session); UserInterface?.Open(session);
} }
void IActivate.Activate(ActivateEventArgs eventArgs) void IActivate.Activate(ActivateEventArgs eventArgs)
{ {
if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) if (!eventArgs.User.TryGetComponent(out IActorComponent? actor))
return; return;
if (!Powered) if (!Powered)

View File

@@ -28,10 +28,8 @@ namespace Content.Server.GameObjects.Components.Conveyor
[RegisterComponent] [RegisterComponent]
public class ConveyorComponent : Component, IInteractUsing public class ConveyorComponent : Component, IInteractUsing
{ {
#pragma warning disable 649
[Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IRobustRandom _random = default!;
#pragma warning restore 649
public override string Name => "Conveyor"; public override string Name => "Conveyor";

View File

@@ -2,6 +2,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.Interactable;
using Content.Shared.Damage; using Content.Shared.Damage;
using Content.Shared.GameObjects.Components.Damage;
using Content.Shared.GameObjects.Components.Interactable; using Content.Shared.GameObjects.Components.Interactable;
using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
@@ -27,12 +28,6 @@ namespace Content.Server.GameObjects.Components.Damage
serializer.DataField(ref _tools, "tools", new List<ToolQuality>()); serializer.DataField(ref _tools, "tools", new List<ToolQuality>());
} }
public override void Initialize()
{
base.Initialize();
Owner.EnsureComponent<DestructibleComponent>();
}
public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs) public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs)
{ {
if (eventArgs.Using.TryGetComponent<ToolComponent>(out var tool)) if (eventArgs.Using.TryGetComponent<ToolComponent>(out var tool))
@@ -56,7 +51,7 @@ namespace Content.Server.GameObjects.Components.Damage
protected bool CallDamage(InteractUsingEventArgs eventArgs, ToolComponent tool) protected bool CallDamage(InteractUsingEventArgs eventArgs, ToolComponent tool)
{ {
if (eventArgs.Target.TryGetComponent<DestructibleComponent>(out var damageable)) if (eventArgs.Target.TryGetComponent<IDamageableComponent>(out var damageable))
{ {
damageable.ChangeDamage(tool.HasQuality(ToolQuality.Welding) damageable.ChangeDamage(tool.HasQuality(ToolQuality.Welding)
? DamageType.Heat ? DamageType.Heat

View File

@@ -1,4 +1,5 @@
using Content.Server.Interfaces; #nullable enable
using Content.Server.Interfaces;
using Content.Server.Interfaces.GameObjects.Components.Items; using Content.Server.Interfaces.GameObjects.Components.Items;
using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Interfaces.GameObjects.Components;
@@ -25,22 +26,24 @@ namespace Content.Server.GameObjects.Components.Disposal
[ComponentReference(typeof(IDisposalTubeComponent))] [ComponentReference(typeof(IDisposalTubeComponent))]
public class DisposalRouterComponent : DisposalJunctionComponent, IActivate public class DisposalRouterComponent : DisposalJunctionComponent, IActivate
{ {
#pragma warning disable 649 [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
[Dependency] private readonly IServerNotifyManager _notifyManager;
#pragma warning restore 649
public override string Name => "DisposalRouter"; public override string Name => "DisposalRouter";
[ViewVariables] [ViewVariables]
private BoundUserInterface _userInterface; private readonly HashSet<string> _tags = new HashSet<string>();
[ViewVariables]
private HashSet<string> _tags;
[ViewVariables] [ViewVariables]
public bool Anchored => public bool Anchored =>
!Owner.TryGetComponent(out CollidableComponent collidable) || !Owner.TryGetComponent(out ICollidableComponent? collidable) ||
collidable.Anchored; collidable.Anchored;
[ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(DisposalRouterUiKey.Key, out var boundUi)
? boundUi
: null;
public override Direction NextDirection(DisposalHolderComponent holder) public override Direction NextDirection(DisposalHolderComponent holder)
{ {
var directions = ConnectableDirections(); var directions = ConnectableDirections();
@@ -53,15 +56,14 @@ namespace Content.Server.GameObjects.Components.Disposal
return Owner.Transform.LocalRotation.GetDir(); return Owner.Transform.LocalRotation.GetDir();
} }
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(DisposalRouterUiKey.Key);
_userInterface.OnReceiveMessage += OnUiReceiveMessage;
_tags = new HashSet<string>(); if (UserInterface != null)
{
UserInterface.OnReceiveMessage += OnUiReceiveMessage;
}
UpdateUserInterface(); UpdateUserInterface();
} }
@@ -73,6 +75,11 @@ namespace Content.Server.GameObjects.Components.Disposal
/// <param name="obj">A user interface message from the client.</param> /// <param name="obj">A user interface message from the client.</param>
private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj) private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj)
{ {
if (obj.Session.AttachedEntity == null)
{
return;
}
var msg = (UiActionMessage) obj.Message; var msg = (UiActionMessage) obj.Message;
if (!PlayerCanUseDisposalTagger(obj.Session.AttachedEntity)) if (!PlayerCanUseDisposalTagger(obj.Session.AttachedEntity))
@@ -112,10 +119,10 @@ namespace Content.Server.GameObjects.Components.Disposal
/// <summary> /// <summary>
/// Gets component data to be used to update the user interface client-side. /// Gets component data to be used to update the user interface client-side.
/// </summary> /// </summary>
/// <returns>Returns a <see cref="SharedDisposalRouterComponent.DisposalRouterBoundUserInterfaceState"/></returns> /// <returns>Returns a <see cref="DisposalRouterUserInterfaceState"/></returns>
private DisposalRouterUserInterfaceState GetUserInterfaceState() private DisposalRouterUserInterfaceState GetUserInterfaceState()
{ {
if(_tags == null || _tags.Count <= 0) if(_tags.Count <= 0)
{ {
return new DisposalRouterUserInterfaceState(""); return new DisposalRouterUserInterfaceState("");
} }
@@ -136,7 +143,7 @@ namespace Content.Server.GameObjects.Components.Disposal
private void UpdateUserInterface() private void UpdateUserInterface()
{ {
var state = GetUserInterfaceState(); var state = GetUserInterfaceState();
_userInterface.SetState(state); UserInterface?.SetState(state);
} }
private void ClickSound() private void ClickSound()
@@ -150,12 +157,12 @@ namespace Content.Server.GameObjects.Components.Disposal
/// <param name="args">Data relevant to the event such as the actor which triggered it.</param> /// <param name="args">Data relevant to the event such as the actor which triggered it.</param>
void IActivate.Activate(ActivateEventArgs args) void IActivate.Activate(ActivateEventArgs args)
{ {
if (!args.User.TryGetComponent(out IActorComponent actor)) if (!args.User.TryGetComponent(out IActorComponent? actor))
{ {
return; return;
} }
if (!args.User.TryGetComponent(out IHandsComponent hands)) if (!args.User.TryGetComponent(out IHandsComponent? hands))
{ {
_notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User, _notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User,
Loc.GetString("You have no hands.")); Loc.GetString("You have no hands."));
@@ -166,13 +173,13 @@ namespace Content.Server.GameObjects.Components.Disposal
if (activeHandEntity == null) if (activeHandEntity == null)
{ {
UpdateUserInterface(); UpdateUserInterface();
_userInterface.Open(actor.playerSession); UserInterface?.Open(actor.playerSession);
} }
} }
public override void OnRemove() public override void OnRemove()
{ {
_userInterface.CloseAll(); UserInterface?.CloseAll();
base.OnRemove(); base.OnRemove();
} }
} }

View File

@@ -1,4 +1,5 @@
using Content.Server.Interfaces; #nullable enable
using Content.Server.Interfaces;
using Content.Server.Interfaces.GameObjects.Components.Items; using Content.Server.Interfaces.GameObjects.Components.Items;
using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Interfaces.GameObjects.Components;
@@ -23,35 +24,38 @@ namespace Content.Server.GameObjects.Components.Disposal
[ComponentReference(typeof(IDisposalTubeComponent))] [ComponentReference(typeof(IDisposalTubeComponent))]
public class DisposalTaggerComponent : DisposalTransitComponent, IActivate public class DisposalTaggerComponent : DisposalTransitComponent, IActivate
{ {
#pragma warning disable 649 [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
[Dependency] private readonly IServerNotifyManager _notifyManager;
#pragma warning restore 649
public override string Name => "DisposalTagger"; public override string Name => "DisposalTagger";
[ViewVariables]
private BoundUserInterface _userInterface;
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
private string _tag = ""; private string _tag = "";
[ViewVariables] [ViewVariables]
public bool Anchored => public bool Anchored =>
!Owner.TryGetComponent(out CollidableComponent collidable) || !Owner.TryGetComponent(out CollidableComponent? collidable) ||
collidable.Anchored; collidable.Anchored;
[ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(DisposalTaggerUiKey.Key, out var boundUi)
? boundUi
: null;
public override Direction NextDirection(DisposalHolderComponent holder) public override Direction NextDirection(DisposalHolderComponent holder)
{ {
holder.Tags.Add(_tag); holder.Tags.Add(_tag);
return base.NextDirection(holder); return base.NextDirection(holder);
} }
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(DisposalTaggerUiKey.Key); if (UserInterface != null)
_userInterface.OnReceiveMessage += OnUiReceiveMessage; {
UserInterface.OnReceiveMessage += OnUiReceiveMessage;
}
UpdateUserInterface(); UpdateUserInterface();
} }
@@ -81,7 +85,7 @@ namespace Content.Server.GameObjects.Components.Disposal
/// </summary> /// </summary>
/// <param name="playerEntity">The player entity.</param> /// <param name="playerEntity">The player entity.</param>
/// <returns>Returns true if the entity can use the configuration interface, and false if it cannot.</returns> /// <returns>Returns true if the entity can use the configuration interface, and false if it cannot.</returns>
private bool PlayerCanUseDisposalTagger(IEntity playerEntity) private bool PlayerCanUseDisposalTagger(IEntity? playerEntity)
{ {
//Need player entity to check if they are still able to use the configuration interface //Need player entity to check if they are still able to use the configuration interface
if (playerEntity == null) if (playerEntity == null)
@@ -98,7 +102,7 @@ namespace Content.Server.GameObjects.Components.Disposal
/// <summary> /// <summary>
/// Gets component data to be used to update the user interface client-side. /// Gets component data to be used to update the user interface client-side.
/// </summary> /// </summary>
/// <returns>Returns a <see cref="SharedDisposalTaggerComponent.DisposalTaggerBoundUserInterfaceState"/></returns> /// <returns>Returns a <see cref="DisposalTaggerUserInterfaceState"/></returns>
private DisposalTaggerUserInterfaceState GetUserInterfaceState() private DisposalTaggerUserInterfaceState GetUserInterfaceState()
{ {
return new DisposalTaggerUserInterfaceState(_tag); return new DisposalTaggerUserInterfaceState(_tag);
@@ -107,7 +111,7 @@ namespace Content.Server.GameObjects.Components.Disposal
private void UpdateUserInterface() private void UpdateUserInterface()
{ {
var state = GetUserInterfaceState(); var state = GetUserInterfaceState();
_userInterface.SetState(state); UserInterface?.SetState(state);
} }
private void ClickSound() private void ClickSound()
@@ -121,12 +125,12 @@ namespace Content.Server.GameObjects.Components.Disposal
/// <param name="args">Data relevant to the event such as the actor which triggered it.</param> /// <param name="args">Data relevant to the event such as the actor which triggered it.</param>
void IActivate.Activate(ActivateEventArgs args) void IActivate.Activate(ActivateEventArgs args)
{ {
if (!args.User.TryGetComponent(out IActorComponent actor)) if (!args.User.TryGetComponent(out IActorComponent? actor))
{ {
return; return;
} }
if (!args.User.TryGetComponent(out IHandsComponent hands)) if (!args.User.TryGetComponent(out IHandsComponent? hands))
{ {
_notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User, _notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User,
Loc.GetString("You have no hands.")); Loc.GetString("You have no hands."));
@@ -137,14 +141,14 @@ namespace Content.Server.GameObjects.Components.Disposal
if (activeHandEntity == null) if (activeHandEntity == null)
{ {
UpdateUserInterface(); UpdateUserInterface();
_userInterface.Open(actor.playerSession); UserInterface?.Open(actor.playerSession);
} }
} }
public override void OnRemove() public override void OnRemove()
{ {
base.OnRemove(); base.OnRemove();
_userInterface.CloseAll(); UserInterface?.CloseAll();
} }
} }
} }

View File

@@ -39,10 +39,8 @@ namespace Content.Server.GameObjects.Components.Disposal
[ComponentReference(typeof(IInteractUsing))] [ComponentReference(typeof(IInteractUsing))]
public class DisposalUnitComponent : SharedDisposalUnitComponent, IInteractHand, IInteractUsing, IDragDropOn public class DisposalUnitComponent : SharedDisposalUnitComponent, IInteractHand, IInteractUsing, IDragDropOn
{ {
#pragma warning disable 649
[Dependency] private readonly IServerNotifyManager _notifyManager = default!; [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IGameTiming _gameTiming = default!;
#pragma warning restore 649
public override string Name => "DisposalUnit"; public override string Name => "DisposalUnit";
@@ -81,9 +79,6 @@ namespace Content.Server.GameObjects.Components.Disposal
[ViewVariables] public IReadOnlyList<IEntity> ContainedEntities => _container.ContainedEntities; [ViewVariables] public IReadOnlyList<IEntity> ContainedEntities => _container.ContainedEntities;
[ViewVariables]
private BoundUserInterface _userInterface = default!;
[ViewVariables] [ViewVariables]
public bool Powered => public bool Powered =>
!Owner.TryGetComponent(out PowerReceiverComponent? receiver) || !Owner.TryGetComponent(out PowerReceiverComponent? receiver) ||
@@ -115,6 +110,13 @@ namespace Content.Server.GameObjects.Components.Disposal
} }
} }
[ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(DisposalUnitUiKey.Key, out var boundUi)
? boundUi
: null;
public bool CanInsert(IEntity entity) public bool CanInsert(IEntity entity)
{ {
if (!Anchored) if (!Anchored)
@@ -161,7 +163,7 @@ namespace Content.Server.GameObjects.Components.Disposal
if (entity.TryGetComponent(out IActorComponent? actor)) if (entity.TryGetComponent(out IActorComponent? actor))
{ {
_userInterface.Close(actor.playerSession); UserInterface?.Close(actor.playerSession);
} }
UpdateVisualState(); UpdateVisualState();
@@ -291,10 +293,10 @@ namespace Content.Server.GameObjects.Components.Disposal
private void UpdateInterface() private void UpdateInterface()
{ {
var state = GetInterfaceState(); var state = GetInterfaceState();
_userInterface.SetState(state); UserInterface?.SetState(state);
} }
private bool PlayerCanUse(IEntity player) private bool PlayerCanUse(IEntity? player)
{ {
if (player == null) if (player == null)
{ {
@@ -472,9 +474,11 @@ namespace Content.Server.GameObjects.Components.Disposal
base.Initialize(); base.Initialize();
_container = ContainerManagerComponent.Ensure<Container>(Name, Owner); _container = ContainerManagerComponent.Ensure<Container>(Name, Owner);
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(DisposalUnitUiKey.Key); if (UserInterface != null)
_userInterface.OnReceiveMessage += OnUiReceiveMessage; {
UserInterface.OnReceiveMessage += OnUiReceiveMessage;
}
UpdateInterface(); UpdateInterface();
} }
@@ -513,7 +517,7 @@ namespace Content.Server.GameObjects.Components.Disposal
_container.ForceRemove(entity); _container.ForceRemove(entity);
} }
_userInterface.CloseAll(); UserInterface?.CloseAll();
_automaticEngageToken?.Cancel(); _automaticEngageToken?.Cancel();
_automaticEngageToken = null; _automaticEngageToken = null;
@@ -571,7 +575,7 @@ namespace Content.Server.GameObjects.Components.Disposal
return false; return false;
} }
_userInterface.Open(actor.playerSession); UserInterface?.Open(actor.playerSession);
return true; return true;
} }

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.Interactable;
@@ -34,10 +35,7 @@ namespace Content.Server.GameObjects.Components.Doors
/// </summary> /// </summary>
private static readonly TimeSpan PowerWiresTimeout = TimeSpan.FromSeconds(5.0); private static readonly TimeSpan PowerWiresTimeout = TimeSpan.FromSeconds(5.0);
private PowerReceiverComponent _powerReceiver; private CancellationTokenSource _powerWiresPulsedTimerCancel = new CancellationTokenSource();
private WiresComponent _wires;
private CancellationTokenSource _powerWiresPulsedTimerCancel;
private bool _powerWiresPulsed; private bool _powerWiresPulsed;
@@ -89,13 +87,15 @@ namespace Content.Server.GameObjects.Components.Doors
private void UpdateWiresStatus() private void UpdateWiresStatus()
{ {
WiresComponent? wires;
var powerLight = new StatusLightData(Color.Yellow, StatusLightState.On, "POWR"); var powerLight = new StatusLightData(Color.Yellow, StatusLightState.On, "POWR");
if (PowerWiresPulsed) if (PowerWiresPulsed)
{ {
powerLight = new StatusLightData(Color.Yellow, StatusLightState.BlinkingFast, "POWR"); powerLight = new StatusLightData(Color.Yellow, StatusLightState.BlinkingFast, "POWR");
} }
else if (_wires.IsWireCut(Wires.MainPower) && else if (Owner.TryGetComponent(out wires) &&
_wires.IsWireCut(Wires.BackupPower)) wires.IsWireCut(Wires.MainPower) &&
wires.IsWireCut(Wires.BackupPower))
{ {
powerLight = new StatusLightData(Color.Red, StatusLightState.On, "POWR"); powerLight = new StatusLightData(Color.Red, StatusLightState.On, "POWR");
} }
@@ -114,12 +114,17 @@ namespace Content.Server.GameObjects.Components.Doors
var safetyStatus = var safetyStatus =
new StatusLightData(Color.Red, Safety ? StatusLightState.On : StatusLightState.Off, "SAFE"); new StatusLightData(Color.Red, Safety ? StatusLightState.On : StatusLightState.Off, "SAFE");
_wires.SetStatus(AirlockWireStatus.PowerIndicator, powerLight); if (!Owner.TryGetComponent(out wires))
_wires.SetStatus(AirlockWireStatus.BoltIndicator, boltStatus); {
_wires.SetStatus(AirlockWireStatus.BoltLightIndicator, boltLightsStatus); return;
_wires.SetStatus(AirlockWireStatus.AIControlIndicator, new StatusLightData(Color.Purple, StatusLightState.BlinkingSlow, "AICT")); }
_wires.SetStatus(AirlockWireStatus.TimingIndicator, timingStatus);
_wires.SetStatus(AirlockWireStatus.SafetyIndicator, safetyStatus); wires.SetStatus(AirlockWireStatus.PowerIndicator, powerLight);
wires.SetStatus(AirlockWireStatus.BoltIndicator, boltStatus);
wires.SetStatus(AirlockWireStatus.BoltLightIndicator, boltLightsStatus);
wires.SetStatus(AirlockWireStatus.AIControlIndicator, new StatusLightData(Color.Purple, StatusLightState.BlinkingSlow, "AICT"));
wires.SetStatus(AirlockWireStatus.TimingIndicator, timingStatus);
wires.SetStatus(AirlockWireStatus.SafetyIndicator, safetyStatus);
/* /*
_wires.SetStatus(6, powerLight); _wires.SetStatus(6, powerLight);
_wires.SetStatus(7, powerLight); _wires.SetStatus(7, powerLight);
@@ -131,14 +136,30 @@ namespace Content.Server.GameObjects.Components.Doors
private void UpdatePowerCutStatus() private void UpdatePowerCutStatus()
{ {
_powerReceiver.PowerDisabled = PowerWiresPulsed || if (!Owner.TryGetComponent(out PowerReceiverComponent? receiver))
_wires.IsWireCut(Wires.MainPower) || {
_wires.IsWireCut(Wires.BackupPower); return;
}
if (PowerWiresPulsed)
{
receiver.PowerDisabled = true;
return;
}
if (!Owner.TryGetComponent(out WiresComponent? wires))
{
return;
}
receiver.PowerDisabled =
wires.IsWireCut(Wires.MainPower) ||
wires.IsWireCut(Wires.BackupPower);
} }
private void UpdateBoltLightStatus() private void UpdateBoltLightStatus()
{ {
if (Owner.TryGetComponent(out AppearanceComponent appearance)) if (Owner.TryGetComponent(out AppearanceComponent? appearance))
{ {
appearance.SetData(DoorVisuals.BoltLights, BoltLightsVisible); appearance.SetData(DoorVisuals.BoltLights, BoltLightsVisible);
} }
@@ -150,7 +171,10 @@ namespace Content.Server.GameObjects.Components.Doors
{ {
base.State = value; base.State = value;
// Only show the maintenance panel if the airlock is closed // Only show the maintenance panel if the airlock is closed
_wires.IsPanelVisible = value != DoorState.Open; if (Owner.TryGetComponent(out WiresComponent? wires))
{
wires.IsPanelVisible = value != DoorState.Open;
}
// If the door is closed, we should look if the bolt was locked while closing // If the door is closed, we should look if the bolt was locked while closing
UpdateBoltLightStatus(); UpdateBoltLightStatus();
} }
@@ -159,29 +183,32 @@ namespace Content.Server.GameObjects.Components.Doors
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
_wires = Owner.GetComponent<WiresComponent>();
_powerReceiver.OnPowerStateChanged += PowerDeviceOnOnPowerStateChanged; if (Owner.TryGetComponent(out PowerReceiverComponent? receiver))
if (Owner.TryGetComponent(out AppearanceComponent appearance))
{ {
appearance.SetData(DoorVisuals.Powered, _powerReceiver.Powered); receiver.OnPowerStateChanged += PowerDeviceOnOnPowerStateChanged;
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
{
appearance.SetData(DoorVisuals.Powered, receiver.Powered);
}
} }
} }
public override void OnRemove() public override void OnRemove()
{ {
if (Owner.TryGetComponent(out _powerReceiver)) if (Owner.TryGetComponent(out PowerReceiverComponent? receiver))
{ {
_powerReceiver.OnPowerStateChanged -= PowerDeviceOnOnPowerStateChanged; receiver.OnPowerStateChanged -= PowerDeviceOnOnPowerStateChanged;
} }
base.OnRemove(); base.OnRemove();
} }
private void PowerDeviceOnOnPowerStateChanged(object sender, PowerStateEventArgs e) private void PowerDeviceOnOnPowerStateChanged(object? sender, PowerStateEventArgs e)
{ {
if (Owner.TryGetComponent(out AppearanceComponent appearance)) if (Owner.TryGetComponent(out AppearanceComponent? appearance))
{ {
appearance.SetData(DoorVisuals.Powered, e.Powered); appearance.SetData(DoorVisuals.Powered, e.Powered);
} }
@@ -192,11 +219,12 @@ namespace Content.Server.GameObjects.Components.Doors
protected override void ActivateImpl(ActivateEventArgs args) protected override void ActivateImpl(ActivateEventArgs args)
{ {
if (_wires.IsPanelOpen) if (Owner.TryGetComponent(out WiresComponent? wires) &&
wires.IsPanelOpen)
{ {
if (args.User.TryGetComponent(out IActorComponent actor)) if (args.User.TryGetComponent(out IActorComponent? actor))
{ {
_wires.OpenInterface(actor.playerSession); wires.OpenInterface(actor.playerSession);
} }
} }
else else
@@ -276,8 +304,7 @@ namespace Content.Server.GameObjects.Components.Doors
case Wires.MainPower: case Wires.MainPower:
case Wires.BackupPower: case Wires.BackupPower:
PowerWiresPulsed = true; PowerWiresPulsed = true;
_powerWiresPulsedTimerCancel?.Cancel(); _powerWiresPulsedTimerCancel.Cancel();
_powerWiresPulsedTimerCancel = new CancellationTokenSource();
Timer.Spawn(PowerWiresTimeout, Timer.Spawn(PowerWiresTimeout,
() => PowerWiresPulsed = false, () => PowerWiresPulsed = false,
_powerWiresPulsedTimerCancel.Token); _powerWiresPulsedTimerCancel.Token);
@@ -381,7 +408,8 @@ namespace Content.Server.GameObjects.Components.Doors
private bool IsPowered() private bool IsPowered()
{ {
return _powerReceiver.Powered; return !Owner.TryGetComponent(out PowerReceiverComponent? receiver)
|| receiver.Powered;
} }
public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs) public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs)
@@ -392,11 +420,12 @@ namespace Content.Server.GameObjects.Components.Doors
if (tool.HasQuality(ToolQuality.Cutting) if (tool.HasQuality(ToolQuality.Cutting)
|| tool.HasQuality(ToolQuality.Multitool)) || tool.HasQuality(ToolQuality.Multitool))
{ {
if (_wires.IsPanelOpen) if (Owner.TryGetComponent(out WiresComponent? wires)
&& wires.IsPanelOpen)
{ {
if (eventArgs.User.TryGetComponent(out IActorComponent actor)) if (eventArgs.User.TryGetComponent(out IActorComponent? actor))
{ {
_wires.OpenInterface(actor.playerSession); wires.OpenInterface(actor.playerSession);
return true; return true;
} }
} }

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using Content.Server.GameObjects.Components.Access; using Content.Server.GameObjects.Components.Access;
@@ -44,10 +45,7 @@ namespace Content.Server.GameObjects.Components.Doors
protected const float AutoCloseDelay = 5; protected const float AutoCloseDelay = 5;
protected float CloseSpeed = AutoCloseDelay; protected float CloseSpeed = AutoCloseDelay;
private AirtightComponent airtightComponent; private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private ICollidableComponent _collidableComponent;
private AppearanceComponent _appearance;
private CancellationTokenSource _cancellationTokenSource;
private static readonly TimeSpan CloseTimeOne = TimeSpan.FromSeconds(0.3f); private static readonly TimeSpan CloseTimeOne = TimeSpan.FromSeconds(0.3f);
private static readonly TimeSpan CloseTimeTwo = TimeSpan.FromSeconds(0.9f); private static readonly TimeSpan CloseTimeTwo = TimeSpan.FromSeconds(0.9f);
@@ -68,21 +66,9 @@ namespace Content.Server.GameObjects.Components.Doors
serializer.DataField(ref _occludes, "occludes", true); serializer.DataField(ref _occludes, "occludes", true);
} }
public override void Initialize()
{
base.Initialize();
airtightComponent = Owner.GetComponent<AirtightComponent>();
_collidableComponent = Owner.GetComponent<ICollidableComponent>();
_appearance = Owner.GetComponent<AppearanceComponent>();
_cancellationTokenSource = new CancellationTokenSource();
}
public override void OnRemove() public override void OnRemove()
{ {
_cancellationTokenSource?.Cancel(); _cancellationTokenSource?.Cancel();
_collidableComponent = null;
_appearance = null;
base.OnRemove(); base.OnRemove();
} }
@@ -104,7 +90,6 @@ namespace Content.Server.GameObjects.Components.Doors
ActivateImpl(eventArgs); ActivateImpl(eventArgs);
} }
void ICollideBehavior.CollideWith(IEntity entity) void ICollideBehavior.CollideWith(IEntity entity)
{ {
if (State != DoorState.Closed) if (State != DoorState.Closed)
@@ -135,8 +120,10 @@ namespace Content.Server.GameObjects.Components.Doors
private void SetAppearance(DoorVisualState state) private void SetAppearance(DoorVisualState state)
{ {
if (_appearance != null || Owner.TryGetComponent(out _appearance)) if (Owner.TryGetComponent(out AppearanceComponent? appearance))
_appearance.SetData(DoorVisuals.VisualState, state); {
appearance.SetData(DoorVisuals.VisualState, state);
}
} }
public virtual bool CanOpen() public virtual bool CanOpen()
@@ -147,7 +134,7 @@ namespace Content.Server.GameObjects.Components.Doors
public bool CanOpen(IEntity user) public bool CanOpen(IEntity user)
{ {
if (!CanOpen()) return false; if (!CanOpen()) return false;
if (!Owner.TryGetComponent(out AccessReader accessReader)) if (!Owner.TryGetComponent(out AccessReader? accessReader))
{ {
return true; return true;
} }
@@ -165,7 +152,7 @@ namespace Content.Server.GameObjects.Components.Doors
Open(); Open();
if (user.TryGetComponent(out HandsComponent hands) && hands.Count == 0) if (user.TryGetComponent(out HandsComponent? hands) && hands.Count == 0)
{ {
EntitySystem.Get<AudioSystem>().PlayFromEntity("/Audio/Effects/bang.ogg", Owner, EntitySystem.Get<AudioSystem>().PlayFromEntity("/Audio/Effects/bang.ogg", Owner,
AudioParams.Default.WithVolume(-2)); AudioParams.Default.WithVolume(-2));
@@ -181,15 +168,22 @@ namespace Content.Server.GameObjects.Components.Doors
State = DoorState.Opening; State = DoorState.Opening;
SetAppearance(DoorVisualState.Opening); SetAppearance(DoorVisualState.Opening);
if (_occludes && Owner.TryGetComponent(out OccluderComponent occluder)) if (_occludes && Owner.TryGetComponent(out OccluderComponent? occluder))
{ {
occluder.Enabled = false; occluder.Enabled = false;
} }
Timer.Spawn(OpenTimeOne, async () => Timer.Spawn(OpenTimeOne, async () =>
{ {
airtightComponent.AirBlocked = false; if (Owner.TryGetComponent(out AirtightComponent? airtight))
_collidableComponent.Hard = false; {
airtight.AirBlocked = false;
}
if (Owner.TryGetComponent(out ICollidableComponent? collidable))
{
collidable.Hard = false;
}
await Timer.Delay(OpenTimeTwo, _cancellationTokenSource.Token); await Timer.Delay(OpenTimeTwo, _cancellationTokenSource.Token);
@@ -208,7 +202,7 @@ namespace Content.Server.GameObjects.Components.Doors
public bool CanClose(IEntity user) public bool CanClose(IEntity user)
{ {
if (!CanClose()) return false; if (!CanClose()) return false;
if (!Owner.TryGetComponent(out AccessReader accessReader)) if (!Owner.TryGetComponent(out AccessReader? accessReader))
{ {
return true; return true;
} }
@@ -229,18 +223,22 @@ namespace Content.Server.GameObjects.Components.Doors
private void CheckCrush() private void CheckCrush()
{ {
if (!Owner.TryGetComponent(out ICollidableComponent? body))
{
return;
}
// Check if collides with something // Check if collides with something
var collidesWith = _collidableComponent.GetCollidingEntities(Vector2.Zero, false); var collidesWith = body.GetCollidingEntities(Vector2.Zero, false);
if (collidesWith.Count() != 0) if (collidesWith.Count() != 0)
{ {
// Crush // Crush
bool hitSomeone = false; bool hitSomeone = false;
foreach (var e in collidesWith) foreach (var e in collidesWith)
{ {
if (!e.TryGetComponent(out StunnableComponent stun) if (!e.TryGetComponent(out StunnableComponent? stun)
|| !e.TryGetComponent(out IDamageableComponent damage) || !e.TryGetComponent(out IDamageableComponent? damage)
|| !e.TryGetComponent(out ICollidableComponent otherBody) || !e.TryGetComponent(out ICollidableComponent? otherBody))
|| !Owner.TryGetComponent(out ICollidableComponent body))
continue; continue;
var percentage = otherBody.WorldAABB.IntersectPercentage(body.WorldAABB); var percentage = otherBody.WorldAABB.IntersectPercentage(body.WorldAABB);
@@ -264,7 +262,8 @@ namespace Content.Server.GameObjects.Components.Doors
public bool Close() public bool Close()
{ {
bool shouldCheckCrush = false; bool shouldCheckCrush = false;
if (_collidableComponent.IsColliding(Vector2.Zero, false))
if (Owner.TryGetComponent(out ICollidableComponent? collidable) && collidable.IsColliding(Vector2.Zero, false))
{ {
if (Safety) if (Safety)
return false; return false;
@@ -276,7 +275,7 @@ namespace Content.Server.GameObjects.Components.Doors
State = DoorState.Closing; State = DoorState.Closing;
OpenTimeCounter = 0; OpenTimeCounter = 0;
SetAppearance(DoorVisualState.Closing); SetAppearance(DoorVisualState.Closing);
if (_occludes && Owner.TryGetComponent(out OccluderComponent occluder)) if (_occludes && Owner.TryGetComponent(out OccluderComponent? occluder))
{ {
occluder.Enabled = true; occluder.Enabled = true;
} }
@@ -288,8 +287,15 @@ namespace Content.Server.GameObjects.Components.Doors
CheckCrush(); CheckCrush();
} }
airtightComponent.AirBlocked = true; if (Owner.TryGetComponent(out AirtightComponent? airtight))
_collidableComponent.Hard = true; {
airtight.AirBlocked = true;
}
if (Owner.TryGetComponent(out ICollidableComponent? body))
{
body.Hard = true;
}
await Timer.Delay(CloseTimeTwo, _cancellationTokenSource.Token); await Timer.Delay(CloseTimeTwo, _cancellationTokenSource.Token);

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Content.Server.GameObjects.Components.Chemistry; using Content.Server.GameObjects.Components.Chemistry;
using Content.Shared.Chemistry; using Content.Shared.Chemistry;
@@ -19,23 +20,27 @@ namespace Content.Server.GameObjects.Components.Fluids
[RegisterComponent] [RegisterComponent]
public class BucketComponent : Component, IInteractUsing public class BucketComponent : Component, IInteractUsing
{ {
#pragma warning disable 649 [Dependency] private readonly ILocalizationManager _localizationManager = default!;
[Dependency] private readonly ILocalizationManager _localizationManager;
#pragma warning restore 649
public override string Name => "Bucket"; public override string Name => "Bucket";
public ReagentUnit MaxVolume public ReagentUnit MaxVolume
{ {
get => _contents.MaxVolume; get => Owner.TryGetComponent(out SolutionComponent? solution) ? solution.MaxVolume : ReagentUnit.Zero;
set => _contents.MaxVolume = value; set
{
if (Owner.TryGetComponent(out SolutionComponent? solution))
{
solution.MaxVolume = value;
}
}
} }
public ReagentUnit CurrentVolume => _contents.CurrentVolume; public ReagentUnit CurrentVolume => Owner.TryGetComponent(out SolutionComponent? solution)
? solution.CurrentVolume
: ReagentUnit.Zero;
private SolutionComponent _contents; private string? _sound;
private string _sound;
/// <inheritdoc /> /// <inheritdoc />
public override void ExposeData(ObjectSerializer serializer) public override void ExposeData(ObjectSerializer serializer)
@@ -47,15 +52,20 @@ namespace Content.Server.GameObjects.Components.Fluids
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_contents = Owner.GetComponent<SolutionComponent>(); Owner.EnsureComponent<SolutionComponent>();
} }
private bool TryGiveToMop(MopComponent mopComponent) private bool TryGiveToMop(MopComponent mopComponent)
{ {
if (!Owner.TryGetComponent(out SolutionComponent? contents))
{
return false;
}
// Let's fill 'er up // Let's fill 'er up
// If this is called the mop should be empty but just in case we'll do Max - Current // If this is called the mop should be empty but just in case we'll do Max - Current
var transferAmount = ReagentUnit.Min(mopComponent.MaxVolume - mopComponent.CurrentVolume, CurrentVolume); var transferAmount = ReagentUnit.Min(mopComponent.MaxVolume - mopComponent.CurrentVolume, CurrentVolume);
var solution = _contents.SplitSolution(transferAmount); var solution = contents.SplitSolution(transferAmount);
if (!mopComponent.Contents.TryAddSolution(solution) || mopComponent.CurrentVolume == 0) if (!mopComponent.Contents.TryAddSolution(solution) || mopComponent.CurrentVolume == 0)
{ {
return false; return false;
@@ -73,7 +83,12 @@ namespace Content.Server.GameObjects.Components.Fluids
public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs) public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs)
{ {
if (!eventArgs.Using.TryGetComponent(out MopComponent mopComponent)) if (!Owner.TryGetComponent(out SolutionComponent? contents))
{
return false;
}
if (!eventArgs.Using.TryGetComponent(out MopComponent? mopComponent))
{ {
return false; return false;
} }
@@ -97,7 +112,7 @@ namespace Content.Server.GameObjects.Components.Fluids
} }
var solution = mopComponent.Contents.SplitSolution(transferAmount); var solution = mopComponent.Contents.SplitSolution(transferAmount);
if (!_contents.TryAddSolution(solution)) if (!contents.TryAddSolution(solution))
{ {
//This really shouldn't happen //This really shouldn't happen
throw new InvalidOperationException(); throw new InvalidOperationException();

View File

@@ -126,18 +126,25 @@ namespace Content.Server.GameObjects.Components.Fluids
_contents.Initialize(); _contents.Initialize();
} }
_snapGrid = Owner.GetComponent<SnapGridComponent>(); _snapGrid = Owner.EnsureComponent<SnapGridComponent>();
// Smaller than 1m^3 for now but realistically this shouldn't be hit // Smaller than 1m^3 for now but realistically this shouldn't be hit
MaxVolume = ReagentUnit.New(1000); MaxVolume = ReagentUnit.New(1000);
// Random sprite state set server-side so it's consistent across all clients // Random sprite state set server-side so it's consistent across all clients
_spriteComponent = Owner.GetComponent<SpriteComponent>(); _spriteComponent = Owner.EnsureComponent<SpriteComponent>();
var robustRandom = IoCManager.Resolve<IRobustRandom>(); var robustRandom = IoCManager.Resolve<IRobustRandom>();
var randomVariant = robustRandom.Next(0, _spriteVariants - 1); var randomVariant = robustRandom.Next(0, _spriteVariants - 1);
if (_spriteComponent.BaseRSIPath != null)
{
var baseName = new ResourcePath(_spriteComponent.BaseRSIPath).FilenameWithoutExtension; var baseName = new ResourcePath(_spriteComponent.BaseRSIPath).FilenameWithoutExtension;
_spriteComponent.LayerSetState(0, $"{baseName}-{randomVariant}"); // TODO: Remove hardcode _spriteComponent.LayerSetState(0, $"{baseName}-{randomVariant}"); // TODO: Remove hardcode
}
// UpdateAppearance should get called soon after this so shouldn't need to call Dirty() here // UpdateAppearance should get called soon after this so shouldn't need to call Dirty() here
UpdateStatus(); UpdateStatus();

View File

@@ -16,10 +16,9 @@ namespace Content.Server.GameObjects.Components.Fluids
[RegisterComponent] [RegisterComponent]
class SprayComponent : Component, IAfterInteract class SprayComponent : Component, IAfterInteract
{ {
#pragma warning disable 649
[Dependency] private readonly IServerNotifyManager _notifyManager = default!; [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
[Dependency] private readonly IServerEntityManager _serverEntityManager = default!; [Dependency] private readonly IServerEntityManager _serverEntityManager = default!;
#pragma warning restore 649
public override string Name => "Spray"; public override string Name => "Spray";
private ReagentUnit _transferAmount; private ReagentUnit _transferAmount;

View File

@@ -37,9 +37,7 @@ namespace Content.Server.GameObjects.Components.GUI
[ComponentReference(typeof(ISharedHandsComponent))] [ComponentReference(typeof(ISharedHandsComponent))]
public class HandsComponent : SharedHandsComponent, IHandsComponent, IBodyPartAdded, IBodyPartRemoved public class HandsComponent : SharedHandsComponent, IHandsComponent, IBodyPartAdded, IBodyPartRemoved
{ {
#pragma warning disable 649
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!; [Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
#pragma warning restore 649
private string? _activeHand; private string? _activeHand;
private uint _nextHand; private uint _nextHand;

View File

@@ -21,7 +21,7 @@ namespace Content.Server.GameObjects.Components.GUI
{ {
base.Initialize(); base.Initialize();
_inventory = Owner.GetComponent<InventoryComponent>(); _inventory = Owner.EnsureComponent<InventoryComponent>();
} }
bool IInventoryController.CanEquip(Slots slot, IEntity entity, bool flagsCheck, out string reason) bool IInventoryController.CanEquip(Slots slot, IEntity entity, bool flagsCheck, out string reason)

View File

@@ -1,11 +1,10 @@
using System; #nullable enable
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Items.Storage;
using Content.Server.GameObjects.EntitySystems.DoAfter; using Content.Server.GameObjects.EntitySystems.DoAfter;
using Content.Server.Interfaces; using Content.Server.Interfaces;
using Content.Shared.GameObjects.Components.GUI; using Content.Shared.GameObjects.Components.GUI;
using Content.Shared.GameObjects.Components.Inventory;
using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Interfaces.GameObjects.Components;
using Robust.Server.GameObjects.Components.UserInterface; using Robust.Server.GameObjects.Components.UserInterface;
@@ -16,7 +15,6 @@ using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Log;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines; using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines;
@@ -25,27 +23,33 @@ namespace Content.Server.GameObjects.Components.GUI
[RegisterComponent] [RegisterComponent]
public sealed class StrippableComponent : SharedStrippableComponent, IDragDrop public sealed class StrippableComponent : SharedStrippableComponent, IDragDrop
{ {
[Dependency] private IServerNotifyManager _notifyManager = default!; [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
public const float StripDelay = 2f; public const float StripDelay = 2f;
[ViewVariables] [ViewVariables]
private BoundUserInterface _userInterface; private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
private InventoryComponent _inventoryComponent; ui.TryGetBoundUserInterface(StrippingUiKey.Key, out var boundUi)
private HandsComponent _handsComponent; ? boundUi
: null;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(StrippingUiKey.Key); if (UserInterface != null)
_userInterface.OnReceiveMessage += HandleUserInterfaceMessage; {
UserInterface.OnReceiveMessage += HandleUserInterfaceMessage;
}
_inventoryComponent = Owner.GetComponent<InventoryComponent>(); Owner.EnsureComponent<InventoryComponent>();
_handsComponent = Owner.GetComponent<HandsComponent>(); Owner.EnsureComponent<HandsComponent>();
_inventoryComponent.OnItemChanged += UpdateSubscribed; if (Owner.TryGetComponent(out InventoryComponent? inventory))
{
inventory.OnItemChanged += UpdateSubscribed;
}
// Initial update. // Initial update.
UpdateSubscribed(); UpdateSubscribed();
@@ -53,10 +57,15 @@ namespace Content.Server.GameObjects.Components.GUI
private void UpdateSubscribed() private void UpdateSubscribed()
{ {
if (UserInterface == null)
{
return;
}
var inventory = GetInventorySlots(); var inventory = GetInventorySlots();
var hands = GetHandSlots(); var hands = GetHandSlots();
_userInterface.SetState(new StrippingBoundUserInterfaceState(inventory, hands)); UserInterface.SetState(new StrippingBoundUserInterfaceState(inventory, hands));
} }
public bool CanDragDrop(DragDropEventArgs eventArgs) public bool CanDragDrop(DragDropEventArgs eventArgs)
@@ -67,7 +76,7 @@ namespace Content.Server.GameObjects.Components.GUI
public bool DragDrop(DragDropEventArgs eventArgs) public bool DragDrop(DragDropEventArgs eventArgs)
{ {
if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) return false; if (!eventArgs.User.TryGetComponent(out IActorComponent? actor)) return false;
OpenUserInterface(actor.playerSession); OpenUserInterface(actor.playerSession);
return true; return true;
@@ -77,9 +86,14 @@ namespace Content.Server.GameObjects.Components.GUI
{ {
var dictionary = new Dictionary<Slots, string>(); var dictionary = new Dictionary<Slots, string>();
foreach (var slot in _inventoryComponent.Slots) if (!Owner.TryGetComponent(out InventoryComponent? inventory))
{ {
dictionary[slot] = _inventoryComponent.GetSlotItem(slot)?.Owner.Name ?? "None"; return dictionary;
}
foreach (var slot in inventory.Slots)
{
dictionary[slot] = inventory.GetSlotItem(slot)?.Owner.Name ?? "None";
} }
return dictionary; return dictionary;
@@ -89,9 +103,14 @@ namespace Content.Server.GameObjects.Components.GUI
{ {
var dictionary = new Dictionary<string, string>(); var dictionary = new Dictionary<string, string>();
foreach (var hand in _handsComponent.Hands) if (!Owner.TryGetComponent(out HandsComponent? hands))
{ {
dictionary[hand] = _handsComponent.GetItem(hand)?.Owner.Name ?? "None"; return dictionary;
}
foreach (var hand in hands.Hands)
{
dictionary[hand] = hands.GetItem(hand)?.Owner.Name ?? "None";
} }
return dictionary; return dictionary;
@@ -99,7 +118,7 @@ namespace Content.Server.GameObjects.Components.GUI
private void OpenUserInterface(IPlayerSession session) private void OpenUserInterface(IPlayerSession session)
{ {
_userInterface.Open(session); UserInterface?.Open(session);
} }
/// <summary> /// <summary>
@@ -336,7 +355,7 @@ namespace Content.Server.GameObjects.Components.GUI
private void HandleUserInterfaceMessage(ServerBoundUserInterfaceMessage obj) private void HandleUserInterfaceMessage(ServerBoundUserInterfaceMessage obj)
{ {
var user = obj.Session.AttachedEntity; var user = obj.Session.AttachedEntity;
if (user == null || !(user.TryGetComponent(out HandsComponent userHands))) return; if (user == null || !(user.TryGetComponent(out HandsComponent? userHands))) return;
var placingItem = userHands.GetActiveHand != null; var placingItem = userHands.GetActiveHand != null;

View File

@@ -1,8 +1,8 @@
using System.Threading.Tasks; #nullable enable
using System.Threading.Tasks;
using Content.Server.GameObjects.Components.Damage; using Content.Server.GameObjects.Components.Damage;
using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.Interactable;
using Content.Server.GameObjects.Components.Power.ApcNetComponents; using Content.Server.GameObjects.Components.Power.ApcNetComponents;
using Content.Server.GameObjects.EntitySystems;
using Content.Server.Interfaces; using Content.Server.Interfaces;
using Content.Shared.GameObjects.Components.Gravity; using Content.Shared.GameObjects.Components.Gravity;
using Content.Shared.GameObjects.Components.Interactable; using Content.Shared.GameObjects.Components.Interactable;
@@ -22,11 +22,6 @@ namespace Content.Server.GameObjects.Components.Gravity
[RegisterComponent] [RegisterComponent]
public class GravityGeneratorComponent : SharedGravityGeneratorComponent, IInteractUsing, IBreakAct, IInteractHand public class GravityGeneratorComponent : SharedGravityGeneratorComponent, IInteractUsing, IBreakAct, IInteractHand
{ {
private BoundUserInterface _userInterface;
private PowerReceiverComponent _powerReceiver;
private SpriteComponent _sprite;
private bool _switchedOn; private bool _switchedOn;
@@ -34,7 +29,7 @@ namespace Content.Server.GameObjects.Components.Gravity
private GravityGeneratorStatus _status; private GravityGeneratorStatus _status;
public bool Powered => _powerReceiver.Powered; public bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
public bool SwitchedOn => _switchedOn; public bool SwitchedOn => _switchedOn;
@@ -64,15 +59,21 @@ namespace Content.Server.GameObjects.Components.Gravity
public override string Name => "GravityGenerator"; public override string Name => "GravityGenerator";
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(GravityGeneratorUiKey.Key, out var boundUi)
? boundUi
: null;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>() if (UserInterface != null)
.GetBoundUserInterface(GravityGeneratorUiKey.Key); {
_userInterface.OnReceiveMessage += HandleUIMessage; UserInterface.OnReceiveMessage += HandleUIMessage;
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>(); }
_sprite = Owner.GetComponent<SpriteComponent>();
_switchedOn = true; _switchedOn = true;
_intact = true; _intact = true;
_status = GravityGeneratorStatus.On; _status = GravityGeneratorStatus.On;
@@ -101,7 +102,7 @@ namespace Content.Server.GameObjects.Components.Gravity
public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs) public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs)
{ {
if (!eventArgs.Using.TryGetComponent(out WelderComponent tool)) if (!eventArgs.Using.TryGetComponent(out WelderComponent? tool))
return false; return false;
if (!await tool.UseTool(eventArgs.User, Owner, 2f, ToolQuality.Welding, 5f)) if (!await tool.UseTool(eventArgs.User, Owner, 2f, ToolQuality.Welding, 5f))
@@ -150,7 +151,7 @@ namespace Content.Server.GameObjects.Components.Gravity
switch (message.Message) switch (message.Message)
{ {
case GeneratorStatusRequestMessage _: case GeneratorStatusRequestMessage _:
_userInterface.SetState(new GeneratorState(Status == GravityGeneratorStatus.On)); UserInterface?.SetState(new GeneratorState(Status == GravityGeneratorStatus.On));
break; break;
case SwitchGeneratorMessage msg: case SwitchGeneratorMessage msg:
_switchedOn = msg.On; _switchedOn = msg.On;
@@ -163,35 +164,51 @@ namespace Content.Server.GameObjects.Components.Gravity
private void OpenUserInterface(IPlayerSession playerSession) private void OpenUserInterface(IPlayerSession playerSession)
{ {
_userInterface.Open(playerSession); UserInterface?.Open(playerSession);
} }
private void MakeBroken() private void MakeBroken()
{ {
_status = GravityGeneratorStatus.Broken; _status = GravityGeneratorStatus.Broken;
_sprite.LayerSetState(0, "broken");
_sprite.LayerSetVisible(1, false); if (Owner.TryGetComponent(out SpriteComponent? sprite))
{
sprite.LayerSetState(0, "broken");
sprite.LayerSetVisible(1, false);
}
} }
private void MakeUnpowered() private void MakeUnpowered()
{ {
_status = GravityGeneratorStatus.Unpowered; _status = GravityGeneratorStatus.Unpowered;
_sprite.LayerSetState(0, "off");
_sprite.LayerSetVisible(1, false); if (Owner.TryGetComponent(out SpriteComponent? sprite))
{
sprite.LayerSetState(0, "off");
sprite.LayerSetVisible(1, false);
}
} }
private void MakeOff() private void MakeOff()
{ {
_status = GravityGeneratorStatus.Off; _status = GravityGeneratorStatus.Off;
_sprite.LayerSetState(0, "off");
_sprite.LayerSetVisible(1, false); if (Owner.TryGetComponent(out SpriteComponent? sprite))
{
sprite.LayerSetState(0, "off");
sprite.LayerSetVisible(1, false);
}
} }
private void MakeOn() private void MakeOn()
{ {
_status = GravityGeneratorStatus.On; _status = GravityGeneratorStatus.On;
_sprite.LayerSetState(0, "on");
_sprite.LayerSetVisible(1, true); if (Owner.TryGetComponent(out SpriteComponent? sprite))
{
sprite.LayerSetState(0, "on");
sprite.LayerSetVisible(1, true);
}
} }
} }

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Linq; using System.Linq;
using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Mobs;
using Content.Server.Interfaces; using Content.Server.Interfaces;
@@ -34,12 +35,8 @@ namespace Content.Server.GameObjects.Components.Instruments
IUse, IUse,
IThrown IThrown
{ {
[Dependency] private readonly IServerNotifyManager _notifyManager = default!;
#pragma warning disable 649 [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IServerNotifyManager _notifyManager;
[Dependency] private readonly IGameTiming _gameTiming;
#pragma warning restore 649
private static readonly TimeSpan OneSecAgo = TimeSpan.FromSeconds(-1); private static readonly TimeSpan OneSecAgo = TimeSpan.FromSeconds(-1);
@@ -47,7 +44,7 @@ namespace Content.Server.GameObjects.Components.Instruments
/// The client channel currently playing the instrument, or null if there's none. /// The client channel currently playing the instrument, or null if there's none.
/// </summary> /// </summary>
[ViewVariables] [ViewVariables]
private IPlayerSession _instrumentPlayer; private IPlayerSession? _instrumentPlayer;
private bool _handheld; private bool _handheld;
@@ -72,9 +69,6 @@ namespace Content.Server.GameObjects.Components.Instruments
[ViewVariables] [ViewVariables]
private int _midiEventCount = 0; private int _midiEventCount = 0;
[ViewVariables]
private BoundUserInterface _userInterface;
/// <summary> /// <summary>
/// Whether the instrument is an item which can be held or not. /// Whether the instrument is an item which can be held or not.
/// </summary> /// </summary>
@@ -95,7 +89,7 @@ namespace Content.Server.GameObjects.Components.Instruments
} }
} }
public IPlayerSession InstrumentPlayer public IPlayerSession? InstrumentPlayer
{ {
get => _instrumentPlayer; get => _instrumentPlayer;
private set private set
@@ -108,11 +102,18 @@ namespace Content.Server.GameObjects.Components.Instruments
_instrumentPlayer = value; _instrumentPlayer = value;
if (value != null) if (value != null)
_instrumentPlayer.PlayerStatusChanged += OnPlayerStatusChanged; _instrumentPlayer!.PlayerStatusChanged += OnPlayerStatusChanged;
} }
} }
private void OnPlayerStatusChanged(object sender, SessionStatusEventArgs e) [ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(InstrumentUiKey.Key, out var boundUi)
? boundUi
: null;
private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
{ {
if (e.Session != _instrumentPlayer || e.NewStatus != SessionStatus.Disconnected) return; if (e.Session != _instrumentPlayer || e.NewStatus != SessionStatus.Disconnected) return;
InstrumentPlayer = null; InstrumentPlayer = null;
@@ -122,8 +123,11 @@ namespace Content.Server.GameObjects.Components.Instruments
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(InstrumentUiKey.Key);
_userInterface.OnClosed += UserInterfaceOnClosed; if (UserInterface != null)
{
UserInterface.OnClosed += UserInterfaceOnClosed;
}
} }
public override void ExposeData(ObjectSerializer serializer) public override void ExposeData(ObjectSerializer serializer)
@@ -137,14 +141,14 @@ namespace Content.Server.GameObjects.Components.Instruments
return new InstrumentState(Playing, _lastSequencerTick); return new InstrumentState(Playing, _lastSequencerTick);
} }
public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession session = null) public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession? session = null)
{ {
base.HandleNetworkMessage(message, channel, session); base.HandleNetworkMessage(message, channel, session);
switch (message) switch (message)
{ {
case InstrumentMidiEventMessage midiEventMsg: case InstrumentMidiEventMessage midiEventMsg:
if (!Playing || session != _instrumentPlayer) return; if (!Playing || session != _instrumentPlayer || InstrumentPlayer == null) return;
var send = true; var send = true;
@@ -231,7 +235,7 @@ namespace Content.Server.GameObjects.Components.Instruments
Clean(); Clean();
SendNetworkMessage(new InstrumentStopMidiMessage()); SendNetworkMessage(new InstrumentStopMidiMessage());
InstrumentPlayer = null; InstrumentPlayer = null;
_userInterface.CloseAll(); UserInterface?.CloseAll();
} }
public void Thrown(ThrownEventArgs eventArgs) public void Thrown(ThrownEventArgs eventArgs)
@@ -239,7 +243,7 @@ namespace Content.Server.GameObjects.Components.Instruments
Clean(); Clean();
SendNetworkMessage(new InstrumentStopMidiMessage()); SendNetworkMessage(new InstrumentStopMidiMessage());
InstrumentPlayer = null; InstrumentPlayer = null;
_userInterface.CloseAll(); UserInterface?.CloseAll();
} }
public void HandSelected(HandSelectedEventArgs eventArgs) public void HandSelected(HandSelectedEventArgs eventArgs)
@@ -255,12 +259,12 @@ namespace Content.Server.GameObjects.Components.Instruments
{ {
Clean(); Clean();
SendNetworkMessage(new InstrumentStopMidiMessage()); SendNetworkMessage(new InstrumentStopMidiMessage());
_userInterface.CloseAll(); UserInterface?.CloseAll();
} }
public void Activate(ActivateEventArgs eventArgs) public void Activate(ActivateEventArgs eventArgs)
{ {
if (Handheld || !eventArgs.User.TryGetComponent(out IActorComponent actor)) return; if (Handheld || !eventArgs.User.TryGetComponent(out IActorComponent? actor)) return;
if (InstrumentPlayer != null) return; if (InstrumentPlayer != null) return;
@@ -270,7 +274,7 @@ namespace Content.Server.GameObjects.Components.Instruments
public bool UseEntity(UseEntityEventArgs eventArgs) public bool UseEntity(UseEntityEventArgs eventArgs)
{ {
if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) return false; if (!eventArgs.User.TryGetComponent(out IActorComponent? actor)) return false;
if (InstrumentPlayer == actor.playerSession) if (InstrumentPlayer == actor.playerSession)
{ {
@@ -291,7 +295,7 @@ namespace Content.Server.GameObjects.Components.Instruments
private void OpenUserInterface(IPlayerSession session) private void OpenUserInterface(IPlayerSession session)
{ {
_userInterface.Open(session); UserInterface?.Open(session);
} }
public override void Update(float delta) public override void Update(float delta)
@@ -302,7 +306,7 @@ namespace Content.Server.GameObjects.Components.Instruments
{ {
InstrumentPlayer = null; InstrumentPlayer = null;
Clean(); Clean();
_userInterface.CloseAll(); UserInterface?.CloseAll();
} }
if ((_batchesDropped >= MaxMidiBatchDropped if ((_batchesDropped >= MaxMidiBatchDropped
@@ -314,9 +318,9 @@ namespace Content.Server.GameObjects.Components.Instruments
SendNetworkMessage(new InstrumentStopMidiMessage()); SendNetworkMessage(new InstrumentStopMidiMessage());
Playing = false; Playing = false;
_userInterface.CloseAll(); UserInterface?.CloseAll();
if (mob.TryGetComponent(out StunnableComponent stun)) if (mob != null && mob.TryGetComponent(out StunnableComponent? stun))
{ {
stun.Stun(1); stun.Stun(1);
Clean(); Clean();

View File

@@ -1,4 +1,5 @@
using System.Threading.Tasks; #nullable enable
using System.Threading.Tasks;
using Content.Server.GameObjects.Components.GUI; using Content.Server.GameObjects.Components.GUI;
using Content.Server.GameObjects.Components.Items.Clothing; using Content.Server.GameObjects.Components.Items.Clothing;
using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Items.Storage;
@@ -29,25 +30,20 @@ namespace Content.Server.GameObjects.Components.Interactable
[RegisterComponent] [RegisterComponent]
internal sealed class HandheldLightComponent : SharedHandheldLightComponent, IUse, IExamine, IInteractUsing, IMapInit internal sealed class HandheldLightComponent : SharedHandheldLightComponent, IUse, IExamine, IInteractUsing, IMapInit
{ {
#pragma warning disable 649 [Dependency] private readonly ISharedNotifyManager _notifyManager = default!;
[Dependency] private readonly ISharedNotifyManager _notifyManager; [Dependency] private readonly ILocalizationManager _localizationManager = default!;
[Dependency] private readonly ILocalizationManager _localizationManager;
#pragma warning restore 649
[ViewVariables(VVAccess.ReadWrite)] public float Wattage { get; set; } = 10; [ViewVariables(VVAccess.ReadWrite)] public float Wattage { get; set; } = 10;
[ViewVariables] private ContainerSlot _cellContainer; [ViewVariables] private ContainerSlot _cellContainer = default!;
private PointLightComponent _pointLight;
private SpriteComponent _spriteComponent;
private ClothingComponent _clothingComponent;
[ViewVariables] [ViewVariables]
private BatteryComponent Cell private BatteryComponent? Cell
{ {
get get
{ {
if (_cellContainer.ContainedEntity == null) return null; if (_cellContainer.ContainedEntity == null) return null;
_cellContainer.ContainedEntity.TryGetComponent(out BatteryComponent cell); _cellContainer.ContainedEntity.TryGetComponent(out BatteryComponent? cell);
return cell; return cell;
} }
} }
@@ -98,11 +94,10 @@ namespace Content.Server.GameObjects.Components.Interactable
{ {
base.Initialize(); base.Initialize();
_pointLight = Owner.GetComponent<PointLightComponent>(); Owner.EnsureComponent<PointLightComponent>();
_spriteComponent = Owner.GetComponent<SpriteComponent>();
Owner.TryGetComponent(out _clothingComponent);
_cellContainer = _cellContainer =
ContainerManagerComponent.Ensure<ContainerSlot>("flashlight_cell_container", Owner, out _); ContainerManagerComponent.Ensure<ContainerSlot>("flashlight_cell_container", Owner, out _);
Dirty(); Dirty();
} }
@@ -179,11 +174,19 @@ namespace Content.Server.GameObjects.Components.Interactable
private void SetState(bool on) private void SetState(bool on)
{ {
_spriteComponent.LayerSetVisible(1, on); if (Owner.TryGetComponent(out SpriteComponent? sprite))
_pointLight.Enabled = on;
if (_clothingComponent != null)
{ {
_clothingComponent.ClothingEquippedPrefix = on ? "On" : "Off"; sprite.LayerSetVisible(1, on);
}
if (Owner.TryGetComponent(out PointLightComponent? light))
{
light.Enabled = on;
}
if (Owner.TryGetComponent(out ClothingComponent? clothing))
{
clothing.ClothingEquippedPrefix = on ? "On" : "Off";
} }
} }
@@ -211,7 +214,7 @@ namespace Content.Server.GameObjects.Components.Interactable
return; return;
} }
if (!user.TryGetComponent(out HandsComponent hands)) if (!user.TryGetComponent(out HandsComponent? hands))
{ {
return; return;
} }

View File

@@ -29,10 +29,8 @@ namespace Content.Server.GameObjects.Components.Interactable
[ComponentReference(typeof(IToolComponent))] [ComponentReference(typeof(IToolComponent))]
public class WelderComponent : ToolComponent, IExamine, IUse, ISuicideAct, ISolutionChange public class WelderComponent : ToolComponent, IExamine, IUse, ISuicideAct, ISolutionChange
{ {
#pragma warning disable 649
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!; [Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
[Dependency] private readonly IServerNotifyManager _notifyManager = default!; [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
#pragma warning restore 649
public override string Name => "Welder"; public override string Name => "Welder";
public override uint? NetID => ContentNetIDs.WELDER; public override uint? NetID => ContentNetIDs.WELDER;

View File

@@ -21,10 +21,8 @@ namespace Content.Server.GameObjects.Components.Items
#pragma warning restore 649 #pragma warning restore 649
public override string Name => "FloorTile"; public override string Name => "FloorTile";
private StackComponent _stack;
private string _outputTile; private string _outputTile;
public override void ExposeData(ObjectSerializer serializer) public override void ExposeData(ObjectSerializer serializer)
{ {
base.ExposeData(serializer); base.ExposeData(serializer);
@@ -34,18 +32,20 @@ namespace Content.Server.GameObjects.Components.Items
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_stack = Owner.GetComponent<StackComponent>(); Owner.EnsureComponent<StackComponent>();
} }
public void AfterInteract(AfterInteractEventArgs eventArgs) public void AfterInteract(AfterInteractEventArgs eventArgs)
{ {
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return; if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
if (!Owner.TryGetComponent(out StackComponent stack)) return;
var attacked = eventArgs.Target; var attacked = eventArgs.Target;
var mapGrid = _mapManager.GetGrid(eventArgs.ClickLocation.GridID); var mapGrid = _mapManager.GetGrid(eventArgs.ClickLocation.GridID);
var tile = mapGrid.GetTileRef(eventArgs.ClickLocation); var tile = mapGrid.GetTileRef(eventArgs.ClickLocation);
var tileDef = (ContentTileDefinition)_tileDefinitionManager[tile.Tile.TypeId]; var tileDef = (ContentTileDefinition)_tileDefinitionManager[tile.Tile.TypeId];
if (tileDef.IsSubFloor && attacked == null && _stack.Use(1)) if (tileDef.IsSubFloor && attacked == null && stack.Use(1))
{ {
var desiredTile = _tileDefinitionManager[_outputTile]; var desiredTile = _tileDefinitionManager[_outputTile];
mapGrid.SetTile(eventArgs.ClickLocation, new Tile(desiredTile.TileId)); mapGrid.SetTile(eventArgs.ClickLocation, new Tile(desiredTile.TileId));

View File

@@ -37,10 +37,8 @@ namespace Content.Server.GameObjects.Components.Items.Storage
public class ServerStorageComponent : SharedStorageComponent, IInteractUsing, IUse, IActivate, IStorageComponent, IDestroyAct, IExAct, public class ServerStorageComponent : SharedStorageComponent, IInteractUsing, IUse, IActivate, IStorageComponent, IDestroyAct, IExAct,
IDragDrop IDragDrop
{ {
#pragma warning disable 649
[Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!;
#pragma warning restore 649
private const string LoggerName = "Storage"; private const string LoggerName = "Storage";

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -39,25 +40,19 @@ namespace Content.Server.GameObjects.Components.Kitchen
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
public class MicrowaveComponent : SharedMicrowaveComponent, IActivate, IInteractUsing, ISolutionChange, ISuicideAct public class MicrowaveComponent : SharedMicrowaveComponent, IActivate, IInteractUsing, ISolutionChange, ISuicideAct
{ {
#pragma warning disable 649 [Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IEntityManager _entityManager; [Dependency] private readonly RecipeManager _recipeManager = default!;
[Dependency] private readonly RecipeManager _recipeManager; [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
[Dependency] private readonly IServerNotifyManager _notifyManager;
#pragma warning restore 649
#region YAMLSERIALIZE #region YAMLSERIALIZE
private int _cookTimeDefault; private int _cookTimeDefault;
private int _cookTimeMultiplier; //For upgrades and stuff I guess? private int _cookTimeMultiplier; //For upgrades and stuff I guess?
private string _badRecipeName; private string _badRecipeName = "";
private string _startCookingSound; private string _startCookingSound = "";
private string _cookingCompleteSound; private string _cookingCompleteSound = "";
#endregion #endregion
#region VIEWVARIABLES [ViewVariables]
[ViewVariables]
private SolutionComponent _solution;
[ViewVariables]
private bool _busy = false; private bool _busy = false;
/// <summary> /// <summary>
@@ -67,20 +62,23 @@ namespace Content.Server.GameObjects.Components.Kitchen
/// </summary> /// </summary>
[ViewVariables] [ViewVariables]
private uint _currentCookTimerTime = 1; private uint _currentCookTimerTime = 1;
#endregion
private bool _powered => _powerReceiver.Powered; private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
private bool _hasContents => _solution.ReagentList.Count > 0 || _storage.ContainedEntities.Count > 0; private bool _hasContents => Owner.TryGetComponent(out SolutionComponent? solution) && (solution.ReagentList.Count > 0 || _storage.ContainedEntities.Count > 0);
private bool _uiDirty = true; private bool _uiDirty = true;
private bool _lostPower = false; private bool _lostPower = false;
private int _currentCookTimeButtonIndex = 0; private int _currentCookTimeButtonIndex = 0;
void ISolutionChange.SolutionChanged(SolutionChangeEventArgs eventArgs) => _uiDirty = true; void ISolutionChange.SolutionChanged(SolutionChangeEventArgs eventArgs) => _uiDirty = true;
private AudioSystem _audioSystem; private AudioSystem _audioSystem = default!;
private AppearanceComponent _appearance; private Container _storage = default!;
private PowerReceiverComponent _powerReceiver;
private BoundUserInterface _userInterface; [ViewVariables]
private Container _storage; private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(MicrowaveUiKey.Key, out var boundUi)
? boundUi
: null;
public override void ExposeData(ObjectSerializer serializer) public override void ExposeData(ObjectSerializer serializer)
{ {
@@ -95,22 +93,21 @@ namespace Content.Server.GameObjects.Components.Kitchen
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_solution ??= Owner.TryGetComponent(out SolutionComponent solutionComponent)
? solutionComponent Owner.EnsureComponent<SolutionComponent>();
: Owner.AddComponent<SolutionComponent>();
_storage = ContainerManagerComponent.Ensure<Container>("microwave_entity_container", Owner, out var existed); _storage = ContainerManagerComponent.Ensure<Container>("microwave_entity_container", Owner, out var existed);
_appearance = Owner.GetComponent<AppearanceComponent>();
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
_audioSystem = EntitySystem.Get<AudioSystem>(); _audioSystem = EntitySystem.Get<AudioSystem>();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(MicrowaveUiKey.Key); if (UserInterface != null)
_userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; {
UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
}
} }
private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage message) private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage message)
{ {
if (!_powered || _busy) if (!Powered || _busy)
{ {
return; return;
} }
@@ -158,13 +155,13 @@ namespace Content.Server.GameObjects.Components.Kitchen
public void OnUpdate() public void OnUpdate()
{ {
if (!_powered) if (!Powered)
{ {
//TODO:If someone cuts power currently, microwave magically keeps going. FIX IT! //TODO:If someone cuts power currently, microwave magically keeps going. FIX IT!
SetAppearance(MicrowaveVisualState.Idle); SetAppearance(MicrowaveVisualState.Idle);
} }
if (_busy && !_powered) if (_busy && !Powered)
{ {
//we lost power while we were cooking/busy! //we lost power while we were cooking/busy!
_lostPower = true; _lostPower = true;
@@ -174,11 +171,11 @@ namespace Content.Server.GameObjects.Components.Kitchen
_uiDirty = true; _uiDirty = true;
} }
if (_uiDirty) if (_uiDirty && Owner.TryGetComponent(out SolutionComponent? solution))
{ {
_userInterface.SetState(new MicrowaveUpdateUserInterfaceState UserInterface?.SetState(new MicrowaveUpdateUserInterfaceState
( (
_solution.Solution.Contents.ToArray(), solution.Solution.Contents.ToArray(),
_storage.ContainedEntities.Select(item => item.Uid).ToArray(), _storage.ContainedEntities.Select(item => item.Uid).ToArray(),
_busy, _busy,
_currentCookTimeButtonIndex, _currentCookTimeButtonIndex,
@@ -190,26 +187,26 @@ namespace Content.Server.GameObjects.Components.Kitchen
private void SetAppearance(MicrowaveVisualState state) private void SetAppearance(MicrowaveVisualState state)
{ {
if (_appearance != null || Owner.TryGetComponent(out _appearance)) if (Owner.TryGetComponent(out AppearanceComponent? appearance))
{ {
_appearance.SetData(PowerDeviceVisuals.VisualState, state); appearance.SetData(PowerDeviceVisuals.VisualState, state);
} }
} }
void IActivate.Activate(ActivateEventArgs eventArgs) void IActivate.Activate(ActivateEventArgs eventArgs)
{ {
if (!eventArgs.User.TryGetComponent(out IActorComponent actor) || !_powered) if (!eventArgs.User.TryGetComponent(out IActorComponent? actor) || !Powered)
{ {
return; return;
} }
_uiDirty = true; _uiDirty = true;
_userInterface.Open(actor.playerSession); UserInterface?.Open(actor.playerSession);
} }
public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs) public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs)
{ {
if (!_powered) if (!Powered)
{ {
_notifyManager.PopupMessage(Owner.Transform.GridPosition, eventArgs.User, _notifyManager.PopupMessage(Owner.Transform.GridPosition, eventArgs.User,
Loc.GetString("It has no power!")); Loc.GetString("It has no power!"));
@@ -232,8 +229,13 @@ namespace Content.Server.GameObjects.Components.Kitchen
return false; return false;
} }
if (!Owner.TryGetComponent(out SolutionComponent? solution))
{
return false;
}
//Get transfer amount. May be smaller than _transferAmount if not enough room //Get transfer amount. May be smaller than _transferAmount if not enough room
var realTransferAmount = ReagentUnit.Min(attackPourable.TransferAmount, _solution.EmptyVolume); var realTransferAmount = ReagentUnit.Min(attackPourable.TransferAmount, solution.EmptyVolume);
if (realTransferAmount <= 0) //Special message if container is full if (realTransferAmount <= 0) //Special message if container is full
{ {
_notifyManager.PopupMessage(Owner.Transform.GridPosition, eventArgs.User, _notifyManager.PopupMessage(Owner.Transform.GridPosition, eventArgs.User,
@@ -243,7 +245,7 @@ namespace Content.Server.GameObjects.Components.Kitchen
//Move units from attackSolution to targetSolution //Move units from attackSolution to targetSolution
var removedSolution = attackSolution.SplitSolution(realTransferAmount); var removedSolution = attackSolution.SplitSolution(realTransferAmount);
if (!_solution.TryAddSolution(removedSolution)) if (!solution.TryAddSolution(removedSolution))
{ {
return false; return false;
} }
@@ -280,6 +282,11 @@ namespace Content.Server.GameObjects.Components.Kitchen
var solidsDict = new Dictionary<string, int>(); var solidsDict = new Dictionary<string, int>();
foreach(var item in _storage.ContainedEntities) foreach(var item in _storage.ContainedEntities)
{ {
if (item.Prototype == null)
{
continue;
}
if(solidsDict.ContainsKey(item.Prototype.ID)) if(solidsDict.ContainsKey(item.Prototype.ID))
{ {
solidsDict[item.Prototype.ID]++; solidsDict[item.Prototype.ID]++;
@@ -303,7 +310,7 @@ namespace Content.Server.GameObjects.Components.Kitchen
} }
// Check recipes // Check recipes
FoodRecipePrototype recipeToCook = null; FoodRecipePrototype? recipeToCook = null;
foreach (var r in _recipeManager.Recipes.Where(r => CanSatisfyRecipe(r, solidsDict) == MicrowaveSuccessState.RecipePass)) foreach (var r in _recipeManager.Recipes.Where(r => CanSatisfyRecipe(r, solidsDict) == MicrowaveSuccessState.RecipePass))
{ {
recipeToCook = r; recipeToCook = r;
@@ -330,7 +337,7 @@ namespace Content.Server.GameObjects.Components.Kitchen
{ {
if (goodMeal) if (goodMeal)
{ {
SubtractContents(recipeToCook); SubtractContents(recipeToCook!);
} }
else else
{ {
@@ -357,12 +364,18 @@ namespace Content.Server.GameObjects.Components.Kitchen
private void VaporizeReagents() private void VaporizeReagents()
{ {
_solution.RemoveAllSolution(); if (Owner.TryGetComponent(out SolutionComponent? solution))
{
solution.RemoveAllSolution();
}
} }
private void VaporizeReagentQuantity(Solution.ReagentQuantity reagentQuantity) private void VaporizeReagentQuantity(Solution.ReagentQuantity reagentQuantity)
{ {
_solution.TryRemoveReagent(reagentQuantity.ReagentId, reagentQuantity.Quantity); if (Owner.TryGetComponent(out SolutionComponent? solution))
{
solution?.TryRemoveReagent(reagentQuantity.ReagentId, reagentQuantity.Quantity);
}
} }
private void VaporizeSolids() private void VaporizeSolids()
@@ -395,9 +408,14 @@ namespace Content.Server.GameObjects.Components.Kitchen
private void SubtractContents(FoodRecipePrototype recipe) private void SubtractContents(FoodRecipePrototype recipe)
{ {
if (!Owner.TryGetComponent(out SolutionComponent? solution))
{
return;
}
foreach(var recipeReagent in recipe.IngredientsReagents) foreach(var recipeReagent in recipe.IngredientsReagents)
{ {
_solution.TryRemoveReagent(recipeReagent.Key, ReagentUnit.New(recipeReagent.Value)); solution?.TryRemoveReagent(recipeReagent.Key, ReagentUnit.New(recipeReagent.Value));
} }
foreach (var recipeSolid in recipe.IngredientsSolids) foreach (var recipeSolid in recipe.IngredientsSolids)
@@ -406,6 +424,11 @@ namespace Content.Server.GameObjects.Components.Kitchen
{ {
foreach (var item in _storage.ContainedEntities) foreach (var item in _storage.ContainedEntities)
{ {
if (item.Prototype == null)
{
continue;
}
if (item.Prototype.ID == recipeSolid.Key) if (item.Prototype.ID == recipeSolid.Key)
{ {
_storage.Remove(item); _storage.Remove(item);
@@ -420,9 +443,14 @@ namespace Content.Server.GameObjects.Components.Kitchen
private MicrowaveSuccessState CanSatisfyRecipe(FoodRecipePrototype recipe, Dictionary<string,int> solids) private MicrowaveSuccessState CanSatisfyRecipe(FoodRecipePrototype recipe, Dictionary<string,int> solids)
{ {
if (!Owner.TryGetComponent(out SolutionComponent? solution))
{
return MicrowaveSuccessState.RecipeFail;
}
foreach (var reagent in recipe.IngredientsReagents) foreach (var reagent in recipe.IngredientsReagents)
{ {
if (!_solution.ContainsReagent(reagent.Key, out var amount)) if (!solution.ContainsReagent(reagent.Key, out var amount))
{ {
return MicrowaveSuccessState.RecipeFail; return MicrowaveSuccessState.RecipeFail;
} }

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.Components.Mobs; #nullable enable
using Content.Server.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.Components; using Content.Shared.GameObjects.Components;
using Content.Shared.Interfaces; using Content.Shared.Interfaces;
using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Interfaces.GameObjects.Components;
@@ -8,6 +9,7 @@ using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components namespace Content.Server.GameObjects.Components
{ {
@@ -15,19 +17,41 @@ namespace Content.Server.GameObjects.Components
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
public class MagicMirrorComponent : SharedMagicMirrorComponent, IActivate public class MagicMirrorComponent : SharedMagicMirrorComponent, IActivate
{ {
private BoundUserInterface _userInterface; [ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(MagicMirrorUiKey.Key, out var boundUi)
? boundUi
: null;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(MagicMirrorUiKey.Key); if (UserInterface != null)
_userInterface.OnReceiveMessage += OnUiReceiveMessage; {
UserInterface.OnReceiveMessage += OnUiReceiveMessage;
}
}
public override void OnRemove()
{
if (UserInterface != null)
{
UserInterface.OnReceiveMessage -= OnUiReceiveMessage;
}
base.OnRemove();
} }
private static void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj) private static void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj)
{ {
if (!obj.Session.AttachedEntity.TryGetComponent(out HumanoidAppearanceComponent looks)) if (obj.Session.AttachedEntity == null)
{
return;
}
if (!obj.Session.AttachedEntity.TryGetComponent(out HumanoidAppearanceComponent? looks))
{ {
return; return;
} }
@@ -70,23 +94,23 @@ namespace Content.Server.GameObjects.Components
public void Activate(ActivateEventArgs eventArgs) public void Activate(ActivateEventArgs eventArgs)
{ {
if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) if (!eventArgs.User.TryGetComponent(out IActorComponent? actor))
{ {
return; return;
} }
if (!eventArgs.User.TryGetComponent(out HumanoidAppearanceComponent looks)) if (!eventArgs.User.TryGetComponent(out HumanoidAppearanceComponent? looks))
{ {
Owner.PopupMessage(eventArgs.User, Loc.GetString("You can't have any hair!")); Owner.PopupMessage(eventArgs.User, Loc.GetString("You can't have any hair!"));
return; return;
} }
_userInterface.Open(actor.playerSession); UserInterface?.Open(actor.playerSession);
var msg = new MagicMirrorInitialDataMessage(looks.Appearance.HairColor, looks.Appearance.FacialHairColor, looks.Appearance.HairStyleName, var msg = new MagicMirrorInitialDataMessage(looks.Appearance.HairColor, looks.Appearance.FacialHairColor, looks.Appearance.HairStyleName,
looks.Appearance.FacialHairStyleName); looks.Appearance.FacialHairStyleName);
_userInterface.SendMessage(msg, actor.playerSession); UserInterface?.SendMessage(msg, actor.playerSession);
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.GameObjects.Components.Power.ApcNetComponents; using Content.Server.GameObjects.Components.Power.ApcNetComponents;
using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems;
@@ -16,6 +17,7 @@ using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Content.Shared.Damage; using Content.Shared.Damage;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Medical namespace Content.Server.GameObjects.Components.Medical
{ {
@@ -23,29 +25,34 @@ namespace Content.Server.GameObjects.Components.Medical
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
public class MedicalScannerComponent : SharedMedicalScannerComponent, IActivate public class MedicalScannerComponent : SharedMedicalScannerComponent, IActivate
{ {
private AppearanceComponent _appearance; private ContainerSlot _bodyContainer = default!;
private BoundUserInterface _userInterface;
private ContainerSlot _bodyContainer;
private readonly Vector2 _ejectOffset = new Vector2(-0.5f, 0f); private readonly Vector2 _ejectOffset = new Vector2(-0.5f, 0f);
public bool IsOccupied => _bodyContainer.ContainedEntity != null; public bool IsOccupied => _bodyContainer.ContainedEntity != null;
private PowerReceiverComponent _powerReceiver; [ViewVariables]
private bool Powered => _powerReceiver.Powered; private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
[ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(MedicalScannerUiKey.Key, out var boundUi)
? boundUi
: null;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_appearance = Owner.GetComponent<AppearanceComponent>(); if (UserInterface != null)
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>() {
.GetBoundUserInterface(MedicalScannerUiKey.Key); UserInterface.OnReceiveMessage += OnUiReceiveMessage;
_userInterface.OnReceiveMessage += OnUiReceiveMessage; }
_bodyContainer = ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-bodyContainer", Owner);
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
//TODO: write this so that it checks for a change in power events and acts accordingly. _bodyContainer = ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-bodyContainer", Owner);
// TODO: write this so that it checks for a change in power events and acts accordingly.
var newState = GetUserInterfaceState(); var newState = GetUserInterfaceState();
_userInterface.SetState(newState); UserInterface?.SetState(newState);
UpdateUserInterface(); UpdateUserInterface();
} }
@@ -62,11 +69,15 @@ namespace Content.Server.GameObjects.Components.Medical
var body = _bodyContainer.ContainedEntity; var body = _bodyContainer.ContainedEntity;
if (body == null) if (body == null)
{ {
_appearance.SetData(MedicalScannerVisuals.Status, MedicalScannerStatus.Open); if (Owner.TryGetComponent(out AppearanceComponent? appearance))
{
appearance?.SetData(MedicalScannerVisuals.Status, MedicalScannerStatus.Open);
};
return EmptyUIState; return EmptyUIState;
} }
if (!body.TryGetComponent(out IDamageableComponent damageable) || if (!body.TryGetComponent(out IDamageableComponent? damageable) ||
damageable.CurrentDamageState == DamageState.Dead) damageable.CurrentDamageState == DamageState.Dead)
{ {
return EmptyUIState; return EmptyUIState;
@@ -86,7 +97,7 @@ namespace Content.Server.GameObjects.Components.Medical
} }
var newState = GetUserInterfaceState(); var newState = GetUserInterfaceState();
_userInterface.SetState(newState); UserInterface?.SetState(newState);
} }
private MedicalScannerStatus GetStatusFromDamageState(DamageState damageState) private MedicalScannerStatus GetStatusFromDamageState(DamageState damageState)
@@ -115,12 +126,15 @@ namespace Content.Server.GameObjects.Components.Medical
private void UpdateAppearance() private void UpdateAppearance()
{ {
_appearance.SetData(MedicalScannerVisuals.Status, GetStatus()); if (Owner.TryGetComponent(out AppearanceComponent? appearance))
{
appearance.SetData(MedicalScannerVisuals.Status, GetStatus());
}
} }
public void Activate(ActivateEventArgs args) public void Activate(ActivateEventArgs args)
{ {
if (!args.User.TryGetComponent(out IActorComponent actor)) if (!args.User.TryGetComponent(out IActorComponent? actor))
{ {
return; return;
} }
@@ -128,7 +142,7 @@ namespace Content.Server.GameObjects.Components.Medical
if (!Powered) if (!Powered)
return; return;
_userInterface.Open(actor.playerSession); UserInterface?.Open(actor.playerSession);
} }
[Verb] [Verb]

View File

@@ -27,7 +27,8 @@ namespace Content.Server.GameObjects.Components.Mining
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
var spriteComponent = Owner.GetComponent<SpriteComponent>();
var spriteComponent = Owner.EnsureComponent<SpriteComponent>();
spriteComponent.LayerSetState(0, _random.Pick(SpriteStates)); spriteComponent.LayerSetState(0, _random.Pick(SpriteStates));
} }

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.EntitySystems.AI; #nullable enable
using Content.Server.GameObjects.EntitySystems.AI;
using Content.Shared.GameObjects.Components.Movement; using Content.Shared.GameObjects.Components.Movement;
using Robust.Server.AI; using Robust.Server.AI;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
@@ -14,23 +15,23 @@ namespace Content.Server.GameObjects.Components.Movement
[RegisterComponent, ComponentReference(typeof(IMoverComponent))] [RegisterComponent, ComponentReference(typeof(IMoverComponent))]
public class AiControllerComponent : Component, IMoverComponent public class AiControllerComponent : Component, IMoverComponent
{ {
private string _logicName; private string? _logicName;
private float _visionRadius; private float _visionRadius;
public override string Name => "AiController"; public override string Name => "AiController";
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public string LogicName public string? LogicName
{ {
get => _logicName; get => _logicName;
set set
{ {
_logicName = value; _logicName = value;
Processor = null; Processor = null!;
} }
} }
public AiLogicProcessor Processor { get; set; } public AiLogicProcessor? Processor { get; set; }
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public float VisionRadius public float VisionRadius
@@ -45,8 +46,7 @@ namespace Content.Server.GameObjects.Components.Movement
base.Initialize(); base.Initialize();
// This component requires a collidable component. // This component requires a collidable component.
if (!Owner.HasComponent<ICollidableComponent>()) Owner.EnsureComponent<CollidableComponent>();
Owner.AddComponent<CollidableComponent>();
EntitySystem.Get<AiSystem>().ProcessorInitialize(this); EntitySystem.Get<AiSystem>().ProcessorInitialize(this);
} }
@@ -74,7 +74,7 @@ namespace Content.Server.GameObjects.Components.Movement
{ {
get get
{ {
if (Owner.TryGetComponent(out MovementSpeedModifierComponent component)) if (Owner.TryGetComponent(out MovementSpeedModifierComponent? component))
{ {
return component.CurrentWalkSpeed; return component.CurrentWalkSpeed;
} }
@@ -91,7 +91,7 @@ namespace Content.Server.GameObjects.Components.Movement
{ {
get get
{ {
if (Owner.TryGetComponent(out MovementSpeedModifierComponent component)) if (Owner.TryGetComponent(out MovementSpeedModifierComponent? component))
{ {
return component.CurrentSprintSpeed; return component.CurrentSprintSpeed;
} }

View File

@@ -24,10 +24,8 @@ namespace Content.Server.GameObjects.Components.Movement
[ComponentReference(typeof(IClimbable))] [ComponentReference(typeof(IClimbable))]
public class ClimbableComponent : SharedClimbableComponent, IDragDropOn public class ClimbableComponent : SharedClimbableComponent, IDragDropOn
{ {
#pragma warning disable 649
[Dependency] private readonly IServerNotifyManager _notifyManager = default!; [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!;
#pragma warning restore 649
/// <summary> /// <summary>
/// The range from which this entity can be climbed. /// The range from which this entity can be climbed.

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Shared.GameObjects.Components.Movement; using Content.Shared.GameObjects.Components.Movement;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
@@ -18,9 +19,7 @@ namespace Content.Server.GameObjects.Components.Movement
[RegisterComponent] [RegisterComponent]
public class ServerPortalComponent : SharedPortalComponent public class ServerPortalComponent : SharedPortalComponent
{ {
#pragma warning disable 649 [Dependency] private readonly IServerEntityManager _serverEntityManager = default!;
[Dependency] private readonly IServerEntityManager _serverEntityManager;
#pragma warning restore 649
// Potential improvements: Different sounds, // Potential improvements: Different sounds,
// Add Gateways // Add Gateways
@@ -28,15 +27,14 @@ namespace Content.Server.GameObjects.Components.Movement
// Put portal above most other things layer-wise // Put portal above most other things layer-wise
// Add telefragging (get entities on connecting portal and force brute damage) // Add telefragging (get entities on connecting portal and force brute damage)
private AppearanceComponent _appearanceComponent; private IEntity? _connectingTeleporter;
private IEntity _connectingTeleporter;
private PortalState _state = PortalState.Pending; private PortalState _state = PortalState.Pending;
[ViewVariables(VVAccess.ReadWrite)] private float _individualPortalCooldown; [ViewVariables(VVAccess.ReadWrite)] private float _individualPortalCooldown;
[ViewVariables] private float _overallPortalCooldown; [ViewVariables] private float _overallPortalCooldown;
[ViewVariables] private bool _onCooldown; [ViewVariables] private bool _onCooldown;
[ViewVariables] private string _departureSound; [ViewVariables] private string _departureSound = "";
[ViewVariables] private string _arrivalSound; [ViewVariables] private string _arrivalSound = "";
public List<IEntity> immuneEntities = new List<IEntity>(); // K public readonly List<IEntity> ImmuneEntities = new List<IEntity>(); // K
[ViewVariables(VVAccess.ReadWrite)] private float _aliveTime; [ViewVariables(VVAccess.ReadWrite)] private float _aliveTime;
public override void ExposeData(ObjectSerializer serializer) public override void ExposeData(ObjectSerializer serializer)
@@ -52,12 +50,6 @@ namespace Content.Server.GameObjects.Components.Movement
serializer.DataField(ref _arrivalSound, "arrival_sound", "/Audio/Effects/teleport_arrival.ogg"); serializer.DataField(ref _arrivalSound, "arrival_sound", "/Audio/Effects/teleport_arrival.ogg");
} }
public override void Initialize()
{
base.Initialize();
_appearanceComponent = Owner.GetComponent<AppearanceComponent>();
}
public override void OnAdd() public override void OnAdd()
{ {
// This will blow up an entity it's attached to // This will blow up an entity it's attached to
@@ -74,13 +66,6 @@ namespace Content.Server.GameObjects.Components.Movement
} }
} }
public override void OnRemove()
{
_appearanceComponent = null;
base.OnRemove();
}
public bool CanBeConnected() public bool CanBeConnected()
{ {
if (_connectingTeleporter == null) if (_connectingTeleporter == null)
@@ -108,23 +93,24 @@ namespace Content.Server.GameObjects.Components.Movement
} }
_state = targetState; _state = targetState;
if (_appearanceComponent != null)
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
{ {
_appearanceComponent.SetData(PortalVisuals.State, _state); appearance.SetData(PortalVisuals.State, _state);
} }
} }
private void releaseCooldown(IEntity entity) private void ReleaseCooldown(IEntity entity)
{ {
if (immuneEntities.Contains(entity)) if (ImmuneEntities.Contains(entity))
{ {
immuneEntities.Remove(entity); ImmuneEntities.Remove(entity);
} }
if (_connectingTeleporter != null && if (_connectingTeleporter != null &&
_connectingTeleporter.TryGetComponent<ServerPortalComponent>(out var otherPortal)) _connectingTeleporter.TryGetComponent<ServerPortalComponent>(out var otherPortal))
{ {
otherPortal.immuneEntities.Remove(entity); otherPortal.ImmuneEntities.Remove(entity);
} }
} }
@@ -142,7 +128,7 @@ namespace Content.Server.GameObjects.Components.Movement
private bool IsEntityPortable(IEntity entity) private bool IsEntityPortable(IEntity entity)
{ {
// TODO: Check if it's slotted etc. Otherwise the slot item itself gets ported. // TODO: Check if it's slotted etc. Otherwise the slot item itself gets ported.
if (!immuneEntities.Contains(entity) && entity.HasComponent<TeleportableComponent>()) if (!ImmuneEntities.Contains(entity) && entity.HasComponent<TeleportableComponent>())
{ {
return true; return true;
} }
@@ -192,7 +178,7 @@ namespace Content.Server.GameObjects.Components.Movement
public void TryPortalEntity(IEntity entity) public void TryPortalEntity(IEntity entity)
{ {
if (immuneEntities.Contains(entity) || _connectingTeleporter == null) if (ImmuneEntities.Contains(entity) || _connectingTeleporter == null)
{ {
return; return;
} }
@@ -208,9 +194,9 @@ namespace Content.Server.GameObjects.Components.Movement
soundPlayer.PlayAtCoords(_arrivalSound, entity.Transform.GridPosition); soundPlayer.PlayAtCoords(_arrivalSound, entity.Transform.GridPosition);
TryChangeState(PortalState.RecentlyTeleported); TryChangeState(PortalState.RecentlyTeleported);
// To stop spam teleporting. Could potentially look at adding a timer to flush this from the portal // To stop spam teleporting. Could potentially look at adding a timer to flush this from the portal
immuneEntities.Add(entity); ImmuneEntities.Add(entity);
_connectingTeleporter.GetComponent<ServerPortalComponent>().immuneEntities.Add(entity); _connectingTeleporter.GetComponent<ServerPortalComponent>().ImmuneEntities.Add(entity);
Timer.Spawn(TimeSpan.FromSeconds(_individualPortalCooldown), () => releaseCooldown(entity)); Timer.Spawn(TimeSpan.FromSeconds(_individualPortalCooldown), () => ReleaseCooldown(entity));
StartCooldown(); StartCooldown();
} }
} }

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Linq; using System.Linq;
using Content.Shared.GameObjects.Components.Movement; using Content.Shared.GameObjects.Components.Movement;
using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Interfaces.GameObjects.Components;
@@ -24,11 +25,10 @@ namespace Content.Server.GameObjects.Components.Movement
[RegisterComponent] [RegisterComponent]
public class ServerTeleporterComponent : Component, IAfterInteract public class ServerTeleporterComponent : Component, IAfterInteract
{ {
#pragma warning disable 649 [Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IMapManager _mapManager; [Dependency] private readonly IServerEntityManager _serverEntityManager = default!;
[Dependency] private readonly IServerEntityManager _serverEntityManager; [Dependency] private readonly IRobustRandom _spreadRandom = default!;
[Dependency] private readonly IRobustRandom _spreadRandom;
#pragma warning restore 649
// TODO: Look at MapManager.Map for Beacons to get all entities on grid // TODO: Look at MapManager.Map for Beacons to get all entities on grid
public ItemTeleporterState State => _state; public ItemTeleporterState State => _state;
@@ -39,15 +39,13 @@ namespace Content.Server.GameObjects.Components.Movement
[ViewVariables] private int _range; [ViewVariables] private int _range;
[ViewVariables] private ItemTeleporterState _state; [ViewVariables] private ItemTeleporterState _state;
[ViewVariables] private TeleporterType _teleporterType; [ViewVariables] private TeleporterType _teleporterType;
[ViewVariables] private string _departureSound; [ViewVariables] private string _departureSound = "";
[ViewVariables] private string _arrivalSound; [ViewVariables] private string _arrivalSound = "";
[ViewVariables] private string _cooldownSound; [ViewVariables] private string? _cooldownSound;
// If the direct OR random teleport will try to avoid hitting collidables // If the direct OR random teleport will try to avoid hitting collidables
[ViewVariables] private bool _avoidCollidable; [ViewVariables] private bool _avoidCollidable;
[ViewVariables] private float _portalAliveTime; [ViewVariables] private float _portalAliveTime;
private AppearanceComponent _appearanceComponent;
public override void ExposeData(ObjectSerializer serializer) public override void ExposeData(ObjectSerializer serializer)
{ {
base.ExposeData(serializer); base.ExposeData(serializer);
@@ -63,22 +61,20 @@ namespace Content.Server.GameObjects.Components.Movement
serializer.DataField(ref _portalAliveTime, "portal_alive_time", 5.0f); // TODO: Change this to 0 before PR? serializer.DataField(ref _portalAliveTime, "portal_alive_time", 5.0f); // TODO: Change this to 0 before PR?
} }
public override void OnRemove()
{
_appearanceComponent = null;
base.OnRemove();
}
private void SetState(ItemTeleporterState newState) private void SetState(ItemTeleporterState newState)
{ {
if (!Owner.TryGetComponent(out AppearanceComponent? appearance))
{
return;
}
if (newState == ItemTeleporterState.Cooldown) if (newState == ItemTeleporterState.Cooldown)
{ {
_appearanceComponent.SetData(TeleporterVisuals.VisualState, TeleporterVisualState.Charging); appearance.SetData(TeleporterVisuals.VisualState, TeleporterVisualState.Charging);
} }
else else
{ {
_appearanceComponent.SetData(TeleporterVisuals.VisualState, TeleporterVisualState.Ready); appearance.SetData(TeleporterVisuals.VisualState, TeleporterVisualState.Ready);
} }
_state = newState; _state = newState;
} }
@@ -149,12 +145,11 @@ namespace Content.Server.GameObjects.Components.Movement
public override void Initialize() public override void Initialize()
{ {
_appearanceComponent = Owner.GetComponent<AppearanceComponent>();
_state = ItemTeleporterState.Off;
base.Initialize(); base.Initialize();
_state = ItemTeleporterState.Off;
} }
private bool emptySpace(IEntity user, Vector2 target) private bool EmptySpace(IEntity user, Vector2 target)
{ {
// TODO: Check the user's spot? Upside is no stacking TPs but downside is they can't unstuck themselves from walls. // TODO: Check the user's spot? Upside is no stacking TPs but downside is they can't unstuck themselves from walls.
foreach (var entity in _serverEntityManager.GetEntitiesIntersecting(user.Transform.MapID, target)) foreach (var entity in _serverEntityManager.GetEntitiesIntersecting(user.Transform.MapID, target))
@@ -167,7 +162,7 @@ namespace Content.Server.GameObjects.Components.Movement
return true; return true;
} }
private Vector2 randomEmptySpot(IEntity user, int range) private Vector2 RandomEmptySpot(IEntity user, int range)
{ {
Vector2 targetVector = user.Transform.GridPosition.Position; Vector2 targetVector = user.Transform.GridPosition.Position;
// Definitely a better way to do this // Definitely a better way to do this
@@ -176,7 +171,7 @@ namespace Content.Server.GameObjects.Components.Movement
var randomRange = _spreadRandom.Next(0, range); var randomRange = _spreadRandom.Next(0, range);
var angle = Angle.FromDegrees(_spreadRandom.Next(0, 359)); var angle = Angle.FromDegrees(_spreadRandom.Next(0, 359));
targetVector = user.Transform.GridPosition.Position + angle.ToVec() * randomRange; targetVector = user.Transform.GridPosition.Position + angle.ToVec() * randomRange;
if (emptySpace(user, targetVector)) if (EmptySpace(user, targetVector))
{ {
return targetVector; return targetVector;
} }
@@ -200,7 +195,7 @@ namespace Content.Server.GameObjects.Components.Movement
Vector2 targetVector; Vector2 targetVector;
if (_avoidCollidable) if (_avoidCollidable)
{ {
targetVector = randomEmptySpot(user, _range); targetVector = RandomEmptySpot(user, _range);
} }
else else
{ {
@@ -227,7 +222,7 @@ namespace Content.Server.GameObjects.Components.Movement
public void Teleport(IEntity user, Vector2 vector) public void Teleport(IEntity user, Vector2 vector)
{ {
// Messy maybe? // Messy maybe?
GridCoordinates targetGrid = new GridCoordinates(vector, user.Transform.GridID); var targetGrid = new GridCoordinates(vector, user.Transform.GridID);
var soundPlayer = EntitySystem.Get<AudioSystem>(); var soundPlayer = EntitySystem.Get<AudioSystem>();
// If portals use those, otherwise just move em over // If portals use those, otherwise just move em over
@@ -240,11 +235,12 @@ namespace Content.Server.GameObjects.Components.Movement
// Arrival portal // Arrival portal
var arrivalPortal = _serverEntityManager.SpawnEntity("Portal", targetGrid); var arrivalPortal = _serverEntityManager.SpawnEntity("Portal", targetGrid);
arrivalPortal.TryGetComponent<ServerPortalComponent>(out var arrivalComponent); if (arrivalPortal.TryGetComponent<ServerPortalComponent>(out var arrivalComponent))
{
// Connect. TODO: If the OnUpdate in ServerPortalComponent is changed this may need to change as well. // Connect. TODO: If the OnUpdate in ServerPortalComponent is changed this may need to change as well.
arrivalComponent.TryConnectPortal(departurePortal); arrivalComponent.TryConnectPortal(departurePortal);
} }
}
else else
{ {
// Departure // Departure

View File

@@ -22,10 +22,8 @@ namespace Content.Server.GameObjects.Components.Movement
[ComponentReference(typeof(IMoverComponent))] [ComponentReference(typeof(IMoverComponent))]
internal class ShuttleControllerComponent : Component, IMoverComponent internal class ShuttleControllerComponent : Component, IMoverComponent
{ {
#pragma warning disable 649
[Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!;
#pragma warning restore 649
private bool _movingUp; private bool _movingUp;
private bool _movingDown; private bool _movingDown;

View File

@@ -48,7 +48,12 @@ namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups
public void AddApc(ApcComponent apc) public void AddApc(ApcComponent apc)
{ {
_apcBatteries.Add(apc, apc.Battery); if (!apc.Owner.TryGetComponent(out BatteryComponent battery))
{
return;
}
_apcBatteries.Add(apc, battery);
} }
public void RemoveApc(ApcComponent apc) public void RemoveApc(ApcComponent apc)

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.GameObjects.Components.Body.Digestive; using Content.Server.GameObjects.Components.Body.Digestive;
using Content.Server.GameObjects.Components.Chemistry; using Content.Server.GameObjects.Components.Chemistry;
@@ -25,24 +26,30 @@ namespace Content.Server.GameObjects.Components.Nutrition
[ComponentReference(typeof(IAfterInteract))] [ComponentReference(typeof(IAfterInteract))]
public class FoodComponent : Component, IUse, IAfterInteract public class FoodComponent : Component, IUse, IAfterInteract
{ {
#pragma warning disable 649 [Dependency] private readonly IEntitySystemManager _entitySystem = default!;
[Dependency] private readonly IEntitySystemManager _entitySystem;
#pragma warning restore 649
public override string Name => "Food"; public override string Name => "Food";
[ViewVariables] [ViewVariables] private string _useSound = "";
private string _useSound; [ViewVariables] private string? _trashPrototype;
[ViewVariables] [ViewVariables] private ReagentUnit _transferAmount;
private string _trashPrototype;
[ViewVariables]
private SolutionComponent _contents;
[ViewVariables]
private ReagentUnit _transferAmount;
private UtensilType _utensilsNeeded; private UtensilType _utensilsNeeded;
public int UsesRemaining => _contents.CurrentVolume == 0 [ViewVariables]
? public int UsesRemaining
0 : Math.Max(1, (int)Math.Ceiling((_contents.CurrentVolume / _transferAmount).Float())); {
get
{
if (!Owner.TryGetComponent(out SolutionComponent? solution))
{
return 0;
}
return solution.CurrentVolume == 0
? 0
: Math.Max(1, (int)Math.Ceiling((solution.CurrentVolume / _transferAmount).Float()));
}
}
public override void ExposeData(ObjectSerializer serializer) public override void ExposeData(ObjectSerializer serializer)
{ {
@@ -60,7 +67,7 @@ namespace Content.Server.GameObjects.Components.Nutrition
{ {
var types = new List<UtensilType>(); var types = new List<UtensilType>();
foreach (UtensilType type in Enum.GetValues(typeof(UtensilType))) foreach (var type in (UtensilType[]) Enum.GetValues(typeof(UtensilType)))
{ {
if ((_utensilsNeeded & type) != 0) if ((_utensilsNeeded & type) != 0)
{ {
@@ -75,8 +82,7 @@ namespace Content.Server.GameObjects.Components.Nutrition
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_contents = Owner.GetComponent<SolutionComponent>(); Owner.EnsureComponent<SolutionComponent>();
} }
bool IUse.UseEntity(UseEntityEventArgs eventArgs) bool IUse.UseEntity(UseEntityEventArgs eventArgs)
@@ -101,8 +107,13 @@ namespace Content.Server.GameObjects.Components.Nutrition
TryUseFood(eventArgs.User, eventArgs.Target); TryUseFood(eventArgs.User, eventArgs.Target);
} }
public virtual bool TryUseFood(IEntity user, IEntity target, UtensilComponent utensilUsed = null) public virtual bool TryUseFood(IEntity? user, IEntity? target, UtensilComponent? utensilUsed = null)
{ {
if (!Owner.TryGetComponent(out SolutionComponent? solution))
{
return false;
}
if (user == null) if (user == null)
{ {
return false; return false;
@@ -116,7 +127,7 @@ namespace Content.Server.GameObjects.Components.Nutrition
var trueTarget = target ?? user; var trueTarget = target ?? user;
if (!trueTarget.TryGetComponent(out StomachComponent stomach)) if (!trueTarget.TryGetComponent(out StomachComponent? stomach))
{ {
return false; return false;
} }
@@ -130,11 +141,11 @@ namespace Content.Server.GameObjects.Components.Nutrition
utensils = new List<UtensilComponent>(); utensils = new List<UtensilComponent>();
var types = UtensilType.None; var types = UtensilType.None;
if (user.TryGetComponent(out HandsComponent hands)) if (user.TryGetComponent(out HandsComponent? hands))
{ {
foreach (var item in hands.GetAllHeldItems()) foreach (var item in hands.GetAllHeldItems())
{ {
if (!item.Owner.TryGetComponent(out UtensilComponent utensil)) if (!item.Owner.TryGetComponent(out UtensilComponent? utensil))
{ {
continue; continue;
} }
@@ -156,11 +167,11 @@ namespace Content.Server.GameObjects.Components.Nutrition
return false; return false;
} }
var transferAmount = ReagentUnit.Min(_transferAmount, _contents.CurrentVolume); var transferAmount = ReagentUnit.Min(_transferAmount, solution.CurrentVolume);
var split = _contents.SplitSolution(transferAmount); var split = solution.SplitSolution(transferAmount);
if (!stomach.TryTransferSolution(split)) if (!stomach.TryTransferSolution(split))
{ {
_contents.TryAddSolution(split); solution.TryAddSolution(split);
trueTarget.PopupMessage(user, Loc.GetString("You can't eat any more!")); trueTarget.PopupMessage(user, Loc.GetString("You can't eat any more!"));
return false; return false;
} }
@@ -194,13 +205,13 @@ namespace Content.Server.GameObjects.Components.Nutrition
var finisher = Owner.EntityManager.SpawnEntity(_trashPrototype, position); var finisher = Owner.EntityManager.SpawnEntity(_trashPrototype, position);
// If the user is holding the item // If the user is holding the item
if (user.TryGetComponent(out HandsComponent handsComponent) && if (user.TryGetComponent(out HandsComponent? handsComponent) &&
handsComponent.IsHolding(Owner)) handsComponent.IsHolding(Owner))
{ {
Owner.Delete(); Owner.Delete();
// Put the trash in the user's hand // Put the trash in the user's hand
if (finisher.TryGetComponent(out ItemComponent item) && if (finisher.TryGetComponent(out ItemComponent? item) &&
handsComponent.CanPutInHand(item)) handsComponent.CanPutInHand(item))
{ {
handsComponent.PutInHand(item); handsComponent.PutInHand(item);

View File

@@ -37,21 +37,24 @@ namespace Content.Server.GameObjects.Components.PDA
[Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!;
[ViewVariables] private Container _idSlot = default!; [ViewVariables] private Container _idSlot = default!;
[ViewVariables] private PointLightComponent _pdaLight = default!;
[ViewVariables] private bool _lightOn; [ViewVariables] private bool _lightOn;
[ViewVariables] private BoundUserInterface _interface = default!;
[ViewVariables] private string _startingIdCard = default!; [ViewVariables] private string _startingIdCard = default!;
[ViewVariables] public bool IdSlotEmpty => _idSlot.ContainedEntities.Count < 1; [ViewVariables] public bool IdSlotEmpty => _idSlot.ContainedEntities.Count < 1;
[ViewVariables] public string? OwnerName { get; private set; } [ViewVariables] public string? OwnerName { get; private set; }
[ViewVariables] public IdCardComponent? ContainedID { get; private set; } [ViewVariables] public IdCardComponent? ContainedID { get; private set; }
[ViewVariables] private AppearanceComponent _appearance = default!;
[ViewVariables] private UplinkAccount? _syndicateUplinkAccount; [ViewVariables] private UplinkAccount? _syndicateUplinkAccount;
[ViewVariables] private readonly PdaAccessSet _accessSet; [ViewVariables] private readonly PdaAccessSet _accessSet;
[ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(PDAUiKey.Key, out var boundUi)
? boundUi
: null;
public PDAComponent() public PDAComponent()
{ {
_accessSet = new PdaAccessSet(this); _accessSet = new PdaAccessSet(this);
@@ -67,11 +70,12 @@ namespace Content.Server.GameObjects.Components.PDA
{ {
base.Initialize(); base.Initialize();
_idSlot = ContainerManagerComponent.Ensure<Container>("pda_entity_container", Owner, out var existed); _idSlot = ContainerManagerComponent.Ensure<Container>("pda_entity_container", Owner, out var existed);
_pdaLight = Owner.GetComponent<PointLightComponent>();
_appearance = Owner.GetComponent<AppearanceComponent>(); if (UserInterface != null)
_interface = Owner.GetComponent<ServerUserInterfaceComponent>() {
.GetBoundUserInterface(PDAUiKey.Key); UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
_interface.OnReceiveMessage += UserInterfaceOnReceiveMessage; }
var idCard = _entityManager.SpawnEntity(_startingIdCard, Owner.Transform.GridPosition); var idCard = _entityManager.SpawnEntity(_startingIdCard, Owner.Transform.GridPosition);
var idCardComponent = idCard.GetComponent<IdCardComponent>(); var idCardComponent = idCard.GetComponent<IdCardComponent>();
_idSlot.Insert(idCardComponent.Owner); _idSlot.Insert(idCardComponent.Owner);
@@ -129,11 +133,11 @@ namespace Content.Server.GameObjects.Components.PDA
var accData = new UplinkAccountData(_syndicateUplinkAccount.AccountHolder, var accData = new UplinkAccountData(_syndicateUplinkAccount.AccountHolder,
_syndicateUplinkAccount.Balance); _syndicateUplinkAccount.Balance);
var listings = _uplinkManager.FetchListings.ToArray(); var listings = _uplinkManager.FetchListings.ToArray();
_interface.SetState(new PDAUpdateState(_lightOn, ownerInfo, accData, listings)); UserInterface?.SetState(new PDAUpdateState(_lightOn, ownerInfo, accData, listings));
} }
else else
{ {
_interface.SetState(new PDAUpdateState(_lightOn, ownerInfo)); UserInterface?.SetState(new PDAUpdateState(_lightOn, ownerInfo));
} }
UpdatePDAAppearance(); UpdatePDAAppearance();
@@ -141,7 +145,10 @@ namespace Content.Server.GameObjects.Components.PDA
private void UpdatePDAAppearance() private void UpdatePDAAppearance()
{ {
_appearance?.SetData(PDAVisuals.FlashlightLit, _lightOn); if (Owner.TryGetComponent(out AppearanceComponent? appearance))
{
appearance.SetData(PDAVisuals.FlashlightLit, _lightOn);
}
} }
public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs) public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs)
@@ -169,7 +176,7 @@ namespace Content.Server.GameObjects.Components.PDA
return; return;
} }
_interface.Open(actor.playerSession); UserInterface?.Open(actor.playerSession);
UpdatePDAAppearance(); UpdatePDAAppearance();
} }
@@ -180,7 +187,7 @@ namespace Content.Server.GameObjects.Components.PDA
return false; return false;
} }
_interface.Open(actor.playerSession); UserInterface?.Open(actor.playerSession);
UpdatePDAAppearance(); UpdatePDAAppearance();
return true; return true;
} }
@@ -217,8 +224,13 @@ namespace Content.Server.GameObjects.Components.PDA
private void ToggleLight() private void ToggleLight()
{ {
if (!Owner.TryGetComponent(out PointLightComponent? light))
{
return;
}
_lightOn = !_lightOn; _lightOn = !_lightOn;
_pdaLight.Enabled = _lightOn; light.Enabled = _lightOn;
EntitySystem.Get<AudioSystem>().PlayFromEntity("/Audio/Items/flashlight_toggle.ogg", Owner); EntitySystem.Get<AudioSystem>().PlayFromEntity("/Audio/Items/flashlight_toggle.ogg", Owner);
UpdatePDAUserInterface(); UpdatePDAUserInterface();
} }

View File

@@ -1,4 +1,5 @@
using System.Threading.Tasks; #nullable enable
using System.Threading.Tasks;
using Content.Shared.GameObjects.Components; using Content.Shared.GameObjects.Components;
using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Interfaces.GameObjects.Components;
@@ -13,24 +14,30 @@ namespace Content.Server.GameObjects.Components.Paper
[RegisterComponent] [RegisterComponent]
public class PaperComponent : SharedPaperComponent, IExamine, IInteractUsing, IUse public class PaperComponent : SharedPaperComponent, IExamine, IInteractUsing, IUse
{ {
private string _content = "";
private BoundUserInterface _userInterface;
private string _content;
private PaperAction _mode; private PaperAction _mode;
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(PaperUiKey.Key, out var boundUi)
? boundUi
: null;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(PaperUiKey.Key); if (UserInterface != null)
_userInterface.OnReceiveMessage += OnUiReceiveMessage; {
_content = ""; UserInterface.OnReceiveMessage += OnUiReceiveMessage;
}
_mode = PaperAction.Read; _mode = PaperAction.Read;
UpdateUserInterface(); UpdateUserInterface();
} }
private void UpdateUserInterface() private void UpdateUserInterface()
{ {
_userInterface.SetState(new PaperBoundUserInterfaceState(_content, _mode)); UserInterface?.SetState(new PaperBoundUserInterfaceState(_content, _mode));
} }
public void Examine(FormattedMessage message, bool inDetailsRange) public void Examine(FormattedMessage message, bool inDetailsRange)
@@ -43,11 +50,12 @@ namespace Content.Server.GameObjects.Components.Paper
public bool UseEntity(UseEntityEventArgs eventArgs) public bool UseEntity(UseEntityEventArgs eventArgs)
{ {
if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) if (!eventArgs.User.TryGetComponent(out IActorComponent? actor))
return false; return false;
_mode = PaperAction.Read; _mode = PaperAction.Read;
UpdateUserInterface(); UpdateUserInterface();
_userInterface.Open(actor.playerSession); UserInterface?.Open(actor.playerSession);
return true; return true;
} }
@@ -59,7 +67,7 @@ namespace Content.Server.GameObjects.Components.Paper
_content += msg.Text + '\n'; _content += msg.Text + '\n';
if (Owner.TryGetComponent(out SpriteComponent sprite)) if (Owner.TryGetComponent(out SpriteComponent? sprite))
{ {
sprite.LayerSetState(1, "paper_words"); sprite.LayerSetState(1, "paper_words");
} }
@@ -71,12 +79,12 @@ namespace Content.Server.GameObjects.Components.Paper
{ {
if (!eventArgs.Using.HasComponent<WriteComponent>()) if (!eventArgs.Using.HasComponent<WriteComponent>())
return false; return false;
if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) if (!eventArgs.User.TryGetComponent(out IActorComponent? actor))
return false; return false;
_mode = PaperAction.Write; _mode = PaperAction.Write;
UpdateUserInterface(); UpdateUserInterface();
_userInterface.Open(actor.playerSession); UserInterface?.Open(actor.playerSession);
return true; return true;
} }
} }

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
using Content.Server.GameObjects.Components.Power.PowerNetComponents; using Content.Server.GameObjects.Components.Power.PowerNetComponents;
using Content.Shared.GameObjects.Components.Power; using Content.Shared.GameObjects.Components.Power;
@@ -20,17 +21,12 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
public class ApcComponent : BaseApcNetComponent, IActivate public class ApcComponent : BaseApcNetComponent, IActivate
{ {
[Dependency] private readonly IGameTiming _gameTiming = default!;
public override string Name => "Apc"; public override string Name => "Apc";
[ViewVariables]
public BatteryComponent Battery { get; private set; }
public bool MainBreakerEnabled { get; private set; } = true; public bool MainBreakerEnabled { get; private set; } = true;
private BoundUserInterface _userInterface;
private AppearanceComponent _appearance;
private ApcChargeState _lastChargeState; private ApcChargeState _lastChargeState;
private TimeSpan _lastChargeStateChange; private TimeSpan _lastChargeStateChange;
@@ -39,7 +35,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
private TimeSpan _lastExternalPowerStateChange; private TimeSpan _lastExternalPowerStateChange;
private float _lastCharge = 0f; private float _lastCharge;
private TimeSpan _lastChargeChange; private TimeSpan _lastChargeChange;
@@ -49,17 +45,27 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
private const int VisualsChangeDelay = 1; private const int VisualsChangeDelay = 1;
#pragma warning disable 649 [ViewVariables]
[Dependency] private readonly IGameTiming _gameTiming; private BoundUserInterface? UserInterface =>
#pragma warning restore 649 Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(ApcUiKey.Key, out var boundUi)
? boundUi
: null;
public BatteryComponent? Battery => Owner.TryGetComponent(out BatteryComponent? batteryComponent) ? batteryComponent : null;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
Battery = Owner.GetComponent<BatteryComponent>();
_appearance = Owner.GetComponent<AppearanceComponent>(); Owner.EnsureComponent<BatteryComponent>();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(ApcUiKey.Key); Owner.EnsureComponent<PowerConsumerComponent>();
_userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
if (UserInterface != null)
{
UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
}
Update(); Update();
} }
@@ -90,15 +96,23 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
{ {
_lastChargeState = newState; _lastChargeState = newState;
_lastChargeStateChange = _gameTiming.CurTime; _lastChargeStateChange = _gameTiming.CurTime;
_appearance.SetData(ApcVisuals.ChargeState, newState);
} if (Owner.TryGetComponent(out AppearanceComponent? appearance))
var newCharge = Battery.CurrentCharge;
if (newCharge != _lastCharge && _lastChargeChange + TimeSpan.FromSeconds(VisualsChangeDelay) < _gameTiming.CurTime)
{ {
_lastCharge = newCharge; appearance.SetData(ApcVisuals.ChargeState, newState);
}
}
Owner.TryGetComponent(out BatteryComponent? battery);
var newCharge = battery?.CurrentCharge;
if (newCharge != null && newCharge != _lastCharge && _lastChargeChange + TimeSpan.FromSeconds(VisualsChangeDelay) < _gameTiming.CurTime)
{
_lastCharge = newCharge.Value;
_lastChargeChange = _gameTiming.CurTime; _lastChargeChange = _gameTiming.CurTime;
_uiDirty = true; _uiDirty = true;
} }
var extPowerState = CalcExtPowerState(); var extPowerState = CalcExtPowerState();
if (extPowerState != _lastExternalPowerState && _lastExternalPowerStateChange + TimeSpan.FromSeconds(VisualsChangeDelay) < _gameTiming.CurTime) if (extPowerState != _lastExternalPowerState && _lastExternalPowerStateChange + TimeSpan.FromSeconds(VisualsChangeDelay) < _gameTiming.CurTime)
{ {
@@ -106,21 +120,33 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
_lastExternalPowerStateChange = _gameTiming.CurTime; _lastExternalPowerStateChange = _gameTiming.CurTime;
_uiDirty = true; _uiDirty = true;
} }
if (_uiDirty)
if (_uiDirty && battery != null && newCharge != null)
{ {
_userInterface.SetState(new ApcBoundInterfaceState(MainBreakerEnabled, extPowerState, newCharge / Battery.MaxCharge)); UserInterface?.SetState(new ApcBoundInterfaceState(MainBreakerEnabled, extPowerState, newCharge.Value / battery.MaxCharge));
_uiDirty = false; _uiDirty = false;
} }
} }
private ApcChargeState CalcChargeState() private ApcChargeState CalcChargeState()
{ {
var chargeFraction = Battery.CurrentCharge / Battery.MaxCharge; if (!Owner.TryGetComponent(out BatteryComponent? battery))
{
return ApcChargeState.Lack;
}
var chargeFraction = battery.CurrentCharge / battery.MaxCharge;
if (chargeFraction > HighPowerThreshold) if (chargeFraction > HighPowerThreshold)
{ {
return ApcChargeState.Full; return ApcChargeState.Full;
} }
var consumer = Owner.GetComponent<PowerConsumerComponent>();
if (!Owner.TryGetComponent(out PowerConsumerComponent? consumer))
{
return ApcChargeState.Full;
}
if (consumer.DrawRate == consumer.ReceivedPower) if (consumer.DrawRate == consumer.ReceivedPower)
{ {
return ApcChargeState.Charging; return ApcChargeState.Charging;
@@ -133,7 +159,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
private ApcExternalPowerState CalcExtPowerState() private ApcExternalPowerState CalcExtPowerState()
{ {
if (!Owner.TryGetComponent(out BatteryStorageComponent batteryStorage)) if (!Owner.TryGetComponent(out BatteryStorageComponent? batteryStorage))
{ {
return ApcExternalPowerState.None; return ApcExternalPowerState.None;
} }
@@ -154,11 +180,12 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
void IActivate.Activate(ActivateEventArgs eventArgs) void IActivate.Activate(ActivateEventArgs eventArgs)
{ {
if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) if (!eventArgs.User.TryGetComponent(out IActorComponent? actor))
{ {
return; return;
} }
_userInterface.Open(actor.playerSession);
UserInterface?.Open(actor.playerSession);
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Content.Server.GameObjects.Components.GUI; using Content.Server.GameObjects.Components.GUI;
using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Items.Storage;
@@ -24,19 +25,14 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece
public abstract class BaseCharger : Component, IActivate, IInteractUsing public abstract class BaseCharger : Component, IActivate, IInteractUsing
{ {
[ViewVariables] [ViewVariables]
private BatteryComponent _heldBattery; private BatteryComponent? _heldBattery;
[ViewVariables] [ViewVariables]
private ContainerSlot _container; private ContainerSlot _container = default!;
[ViewVariables]
private PowerReceiverComponent _powerReceiver;
[ViewVariables] [ViewVariables]
private CellChargerStatus _status; private CellChargerStatus _status;
private AppearanceComponent _appearanceComponent;
[ViewVariables] [ViewVariables]
private int _chargeRate; private int _chargeRate;
@@ -53,16 +49,25 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
Owner.EnsureComponent<PowerReceiverComponent>();
_container = ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-powerCellContainer", Owner); _container = ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-powerCellContainer", Owner);
_appearanceComponent = Owner.GetComponent<AppearanceComponent>();
// Default state in the visualizer is OFF, so when this gets powered on during initialization it will generally show empty // Default state in the visualizer is OFF, so when this gets powered on during initialization it will generally show empty
_powerReceiver.OnPowerStateChanged += PowerUpdate; if (Owner.TryGetComponent(out PowerReceiverComponent? receiver))
{
receiver.OnPowerStateChanged += PowerUpdate;
}
} }
public override void OnRemove() public override void OnRemove()
{ {
_powerReceiver.OnPowerStateChanged -= PowerUpdate; if (Owner.TryGetComponent(out PowerReceiverComponent? receiver))
{
receiver.OnPowerStateChanged -= PowerUpdate;
}
_heldBattery = null;
base.OnRemove(); base.OnRemove();
} }
@@ -97,12 +102,12 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece
_container.Remove(heldItem); _container.Remove(heldItem);
_heldBattery = null; _heldBattery = null;
if (user.TryGetComponent(out HandsComponent handsComponent)) if (user.TryGetComponent(out HandsComponent? handsComponent))
{ {
handsComponent.PutInHandOrDrop(heldItem.GetComponent<ItemComponent>()); handsComponent.PutInHandOrDrop(heldItem.GetComponent<ItemComponent>());
} }
if (heldItem.TryGetComponent(out ServerBatteryBarrelComponent batteryBarrelComponent)) if (heldItem.TryGetComponent(out ServerBatteryBarrelComponent? batteryBarrelComponent))
{ {
batteryBarrelComponent.UpdateAppearance(); batteryBarrelComponent.UpdateAppearance();
} }
@@ -110,7 +115,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece
UpdateStatus(); UpdateStatus();
} }
private void PowerUpdate(object sender, PowerStateEventArgs eventArgs) private void PowerUpdate(object? sender, PowerStateEventArgs eventArgs)
{ {
UpdateStatus(); UpdateStatus();
} }
@@ -125,7 +130,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece
data.Visibility = VerbVisibility.Invisible; data.Visibility = VerbVisibility.Invisible;
return; return;
} }
if (!user.TryGetComponent(out HandsComponent handsComponent)) if (!user.TryGetComponent(out HandsComponent? handsComponent))
{ {
data.Visibility = VerbVisibility.Invisible; data.Visibility = VerbVisibility.Invisible;
return; return;
@@ -143,7 +148,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece
protected override void Activate(IEntity user, BaseCharger component) protected override void Activate(IEntity user, BaseCharger component)
{ {
if (!user.TryGetComponent(out HandsComponent handsComponent)) if (!user.TryGetComponent(out HandsComponent? handsComponent))
{ {
return; return;
} }
@@ -186,7 +191,8 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece
private CellChargerStatus GetStatus() private CellChargerStatus GetStatus()
{ {
if (!_powerReceiver.Powered) if (Owner.TryGetComponent(out PowerReceiverComponent? receiver) &&
!receiver.Powered)
{ {
return CellChargerStatus.Off; return CellChargerStatus.Off;
} }
@@ -227,34 +233,39 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece
{ {
// Not called UpdateAppearance just because it messes with the load // Not called UpdateAppearance just because it messes with the load
var status = GetStatus(); var status = GetStatus();
if (_status == status) if (_status == status ||
!Owner.TryGetComponent(out PowerReceiverComponent? receiver))
{ {
return; return;
} }
_status = status; _status = status;
Owner.TryGetComponent(out AppearanceComponent? appearance);
switch (_status) switch (_status)
{ {
// Update load just in case // Update load just in case
case CellChargerStatus.Off: case CellChargerStatus.Off:
_powerReceiver.Load = 0; receiver.Load = 0;
_appearanceComponent?.SetData(CellVisual.Light, CellChargerStatus.Off); appearance?.SetData(CellVisual.Light, CellChargerStatus.Off);
break; break;
case CellChargerStatus.Empty: case CellChargerStatus.Empty:
_powerReceiver.Load = 0; receiver.Load = 0;
_appearanceComponent?.SetData(CellVisual.Light, CellChargerStatus.Empty); ; appearance?.SetData(CellVisual.Light, CellChargerStatus.Empty);
break; break;
case CellChargerStatus.Charging: case CellChargerStatus.Charging:
_powerReceiver.Load = (int) (_chargeRate / _transferEfficiency); receiver.Load = (int) (_chargeRate / _transferEfficiency);
_appearanceComponent?.SetData(CellVisual.Light, CellChargerStatus.Charging); appearance?.SetData(CellVisual.Light, CellChargerStatus.Charging);
break; break;
case CellChargerStatus.Charged: case CellChargerStatus.Charged:
_powerReceiver.Load = 0; receiver.Load = 0;
_appearanceComponent?.SetData(CellVisual.Light, CellChargerStatus.Charged); appearance?.SetData(CellVisual.Light, CellChargerStatus.Charged);
break; break;
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
_appearanceComponent?.SetData(CellVisual.Occupied, _container.ContainedEntity != null);
appearance?.SetData(CellVisual.Occupied, _container.ContainedEntity != null);
} }
public void OnUpdate(float frameTime) //todo: make single system for this public void OnUpdate(float frameTime) //todo: make single system for this
@@ -268,10 +279,17 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece
private void TransferPower(float frameTime) private void TransferPower(float frameTime)
{ {
if (!_powerReceiver.Powered) if (Owner.TryGetComponent(out PowerReceiverComponent? receiver) &&
!receiver.Powered)
{ {
return; return;
} }
if (_heldBattery == null)
{
return;
}
_heldBattery.CurrentCharge += _chargeRate * frameTime; _heldBattery.CurrentCharge += _chargeRate * frameTime;
// Just so the sprite won't be set to 99.99999% visibility // Just so the sprite won't be set to 99.99999% visibility
if (_heldBattery.MaxCharge - _heldBattery.CurrentCharge < 0.01) if (_heldBattery.MaxCharge - _heldBattery.CurrentCharge < 0.01)

View File

@@ -108,7 +108,11 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece
public void UpdateColor() public void UpdateColor()
{ {
var sprite = Owner.GetComponent<SpriteComponent>(); if (!Owner.TryGetComponent(out SpriteComponent sprite))
{
return;
}
sprite.Color = Color; sprite.Color = Color;
} }

View File

@@ -225,14 +225,18 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece
{ {
base.Initialize(); base.Initialize();
Owner.GetComponent<PowerReceiverComponent>().OnPowerStateChanged += UpdateLight; Owner.EnsureComponent<PowerReceiverComponent>().OnPowerStateChanged += UpdateLight;
_lightBulbContainer = ContainerManagerComponent.Ensure<ContainerSlot>("light_bulb", Owner); _lightBulbContainer = ContainerManagerComponent.Ensure<ContainerSlot>("light_bulb", Owner);
} }
public override void OnRemove() public override void OnRemove()
{ {
Owner.GetComponent<PowerReceiverComponent>().OnPowerStateChanged -= UpdateLight; if (Owner.TryGetComponent(out PowerReceiverComponent receiver))
{
receiver.OnPowerStateChanged -= UpdateLight;
}
base.OnRemove(); base.OnRemove();
} }

View File

@@ -13,12 +13,9 @@ namespace Content.Server.GameObjects.Components.Power
{ {
public override string Name => "PowerCell"; public override string Name => "PowerCell";
private AppearanceComponent _appearance;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_appearance = Owner.GetComponent<AppearanceComponent>();
CurrentCharge = MaxCharge; CurrentCharge = MaxCharge;
UpdateVisuals(); UpdateVisuals();
} }
@@ -31,7 +28,10 @@ namespace Content.Server.GameObjects.Components.Power
private void UpdateVisuals() private void UpdateVisuals()
{ {
_appearance?.SetData(PowerCellVisuals.ChargeLevel, CurrentCharge / MaxCharge); if (Owner.TryGetComponent(out AppearanceComponent appearance))
{
appearance.SetData(PowerCellVisuals.ChargeLevel, CurrentCharge / MaxCharge);
}
} }
} }
} }

View File

@@ -31,8 +31,9 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_battery = Owner.GetComponent<BatteryComponent>();
_supplier = Owner.GetComponent<PowerSupplierComponent>(); _battery = Owner.EnsureComponent<BatteryComponent>();
_supplier = Owner.EnsureComponent<PowerSupplierComponent>();
UpdateSupplyRate(); UpdateSupplyRate();
} }

View File

@@ -31,8 +31,9 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_battery = Owner.GetComponent<BatteryComponent>();
Consumer = Owner.GetComponent<PowerConsumerComponent>(); _battery = Owner.EnsureComponent<BatteryComponent>();
Consumer = Owner.EnsureComponent<PowerConsumerComponent>();
UpdateDrawRate(); UpdateDrawRate();
} }

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using Content.Shared.GameObjects.Components.Power; using Content.Shared.GameObjects.Components.Power;
using Content.Shared.Utility; using Content.Shared.Utility;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
@@ -16,13 +17,11 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents
[RegisterComponent] [RegisterComponent]
public class SmesComponent : Component public class SmesComponent : Component
{ {
[Dependency] private readonly IGameTiming _gameTiming = default!;
public override string Name => "Smes"; public override string Name => "Smes";
private BatteryComponent _battery; private int _lastChargeLevel;
private AppearanceComponent _appearance;
private int _lastChargeLevel = 0;
private TimeSpan _lastChargeLevelChange; private TimeSpan _lastChargeLevelChange;
@@ -32,15 +31,12 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents
private const int VisualsChangeDelay = 1; private const int VisualsChangeDelay = 1;
#pragma warning disable 649
[Dependency] private readonly IGameTiming _gameTiming;
#pragma warning restore 649
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_battery = Owner.GetComponent<BatteryComponent>();
_appearance = Owner.GetComponent<AppearanceComponent>(); Owner.EnsureComponent<BatteryComponent>();
Owner.EnsureComponent<AppearanceComponent>();
} }
public void OnUpdate() public void OnUpdate()
@@ -50,7 +46,11 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents
{ {
_lastChargeLevel = newLevel; _lastChargeLevel = newLevel;
_lastChargeLevelChange = _gameTiming.CurTime; _lastChargeLevelChange = _gameTiming.CurTime;
_appearance.SetData(SmesVisuals.LastChargeLevel, newLevel);
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
{
appearance.SetData(SmesVisuals.LastChargeLevel, newLevel);
}
} }
var newChargeState = GetNewChargeState(); var newChargeState = GetNewChargeState();
@@ -58,13 +58,22 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents
{ {
_lastChargeState = newChargeState; _lastChargeState = newChargeState;
_lastChargeStateChange = _gameTiming.CurTime; _lastChargeStateChange = _gameTiming.CurTime;
_appearance.SetData(SmesVisuals.LastChargeState, newChargeState);
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
{
appearance.SetData(SmesVisuals.LastChargeState, newChargeState);
}
} }
} }
private int GetNewChargeLevel() private int GetNewChargeLevel()
{ {
return ContentHelpers.RoundToLevels(_battery.CurrentCharge, _battery.MaxCharge, 6); if (!Owner.TryGetComponent(out BatteryComponent? battery))
{
return 0;
}
return ContentHelpers.RoundToLevels(battery.CurrentCharge, battery.MaxCharge, 6);
} }
private ChargeState GetNewChargeState() private ChargeState GetNewChargeState()

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.Components.Power.ApcNetComponents; #nullable enable
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components.Power; using Content.Shared.GameObjects.Components.Power;
using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Interfaces.GameObjects.Components;
@@ -7,6 +8,7 @@ using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Power.PowerNetComponents namespace Content.Server.GameObjects.Components.Power.PowerNetComponents
{ {
@@ -14,28 +16,34 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
public class SolarControlConsoleComponent : SharedSolarControlConsoleComponent, IActivate public class SolarControlConsoleComponent : SharedSolarControlConsoleComponent, IActivate
{ {
#pragma warning disable 649 [Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
[Dependency] private IEntitySystemManager _entitySystemManager;
#pragma warning restore 649
private BoundUserInterface _userInterface; private PowerSolarSystem _powerSolarSystem = default!;
private PowerReceiverComponent _powerReceiver; private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
private PowerSolarSystem _powerSolarSystem;
private bool Powered => _powerReceiver.Powered; [ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(SolarControlConsoleUiKey.Key, out var boundUi)
? boundUi
: null;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(SolarControlConsoleUiKey.Key); if (UserInterface != null)
_userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; {
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>(); UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
}
Owner.EnsureComponent<PowerReceiverComponent>();
_powerSolarSystem = _entitySystemManager.GetEntitySystem<PowerSolarSystem>(); _powerSolarSystem = _entitySystemManager.GetEntitySystem<PowerSolarSystem>();
} }
public void UpdateUIState() public void UpdateUIState()
{ {
_userInterface.SetState(new SolarControlConsoleBoundInterfaceState(_powerSolarSystem.TargetPanelRotation, _powerSolarSystem.TargetPanelVelocity, _powerSolarSystem.TotalPanelPower, _powerSolarSystem.TowardsSun)); UserInterface?.SetState(new SolarControlConsoleBoundInterfaceState(_powerSolarSystem.TargetPanelRotation, _powerSolarSystem.TargetPanelVelocity, _powerSolarSystem.TotalPanelPower, _powerSolarSystem.TowardsSun));
} }
private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage obj) private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage obj)
@@ -57,7 +65,7 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents
void IActivate.Activate(ActivateEventArgs eventArgs) void IActivate.Activate(ActivateEventArgs eventArgs)
{ {
if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) if (!eventArgs.User.TryGetComponent(out IActorComponent? actor))
{ {
return; return;
} }
@@ -69,7 +77,7 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents
// always update the UI immediately before opening, just in case // always update the UI immediately before opening, just in case
UpdateUIState(); UpdateUIState();
_userInterface.Open(actor.playerSession); UserInterface?.Open(actor.playerSession);
} }
} }
} }

View File

@@ -15,17 +15,16 @@ namespace Content.Server.GameObjects.Components.Projectiles
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
if (!Owner.HasComponent<ExplosiveComponent>())
{ Owner.EnsureComponent<ExplosiveComponent>();
Logger.Error("ExplosiveProjectiles need an ExplosiveComponent");
throw new InvalidOperationException();
}
} }
void ICollideBehavior.CollideWith(IEntity entity) void ICollideBehavior.CollideWith(IEntity entity)
{ {
var explosiveComponent = Owner.GetComponent<ExplosiveComponent>(); if (Owner.TryGetComponent(out ExplosiveComponent explosive))
explosiveComponent.Explosion(); {
explosive.Explosion();
}
} }
// Projectile should handle the deleting // Projectile should handle the deleting

View File

@@ -31,10 +31,7 @@ namespace Content.Server.GameObjects.Components.Projectiles
{ {
base.Initialize(); base.Initialize();
// Shouldn't be using this without a ProjectileComponent because it will just immediately collide with thrower // Shouldn't be using this without a ProjectileComponent because it will just immediately collide with thrower
if (!Owner.HasComponent<ProjectileComponent>()) Owner.EnsureComponent<ProjectileComponent>();
{
throw new InvalidOperationException();
}
} }
void ICollideBehavior.CollideWith(IEntity entity) void ICollideBehavior.CollideWith(IEntity entity)

View File

@@ -12,10 +12,8 @@ namespace Content.Server.GameObjects.Components
[RegisterComponent] [RegisterComponent]
class RadioComponent : Component, IUse, IListen class RadioComponent : Component, IUse, IListen
{ {
#pragma warning disable 649
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!; [Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
[Dependency] private readonly IServerNotifyManager _notifyManager = default!; [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
#pragma warning restore 649
public override string Name => "Radio"; public override string Name => "Radio";

View File

@@ -28,9 +28,7 @@ namespace Content.Server.GameObjects.Components.Recycling
[RegisterComponent] [RegisterComponent]
public class RecyclerComponent : Component, ICollideBehavior public class RecyclerComponent : Component, ICollideBehavior
{ {
#pragma warning disable 649
[Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!;
#pragma warning restore 649
public override string Name => "Recycler"; public override string Name => "Recycler";

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -25,15 +26,12 @@ namespace Content.Server.GameObjects.Components.Research
{ {
public const int VolumePerSheet = 3750; public const int VolumePerSheet = 3750;
private BoundUserInterface _userInterface;
[ViewVariables] [ViewVariables]
public Queue<LatheRecipePrototype> Queue { get; } = new Queue<LatheRecipePrototype>(); public Queue<LatheRecipePrototype> Queue { get; } = new Queue<LatheRecipePrototype>();
[ViewVariables] [ViewVariables]
public bool Producing { get; private set; } = false; public bool Producing { get; private set; }
private AppearanceComponent _appearance;
private LatheState _state = LatheState.Base; private LatheState _state = LatheState.Base;
protected virtual LatheState State protected virtual LatheState State
@@ -42,19 +40,26 @@ namespace Content.Server.GameObjects.Components.Research
set => _state = value; set => _state = value;
} }
private LatheRecipePrototype _producingRecipe = null; private LatheRecipePrototype? _producingRecipe;
private PowerReceiverComponent _powerReceiver; private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
private bool Powered => _powerReceiver.Powered;
private static readonly TimeSpan InsertionTime = TimeSpan.FromSeconds(0.9f); private static readonly TimeSpan InsertionTime = TimeSpan.FromSeconds(0.9f);
[ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(LatheUiKey.Key, out var boundUi)
? boundUi
: null;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(LatheUiKey.Key);
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; if (UserInterface != null)
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>(); {
_appearance = Owner.GetComponent<AppearanceComponent>(); UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
}
} }
private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage message) private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage message)
@@ -66,28 +71,28 @@ namespace Content.Server.GameObjects.Components.Research
{ {
case LatheQueueRecipeMessage msg: case LatheQueueRecipeMessage msg:
_prototypeManager.TryIndex(msg.ID, out LatheRecipePrototype recipe); _prototypeManager.TryIndex(msg.ID, out LatheRecipePrototype recipe);
if (recipe != null) if (recipe != null!)
for (var i = 0; i < msg.Quantity; i++) for (var i = 0; i < msg.Quantity; i++)
{ {
Queue.Enqueue(recipe); Queue.Enqueue(recipe);
_userInterface.SendMessage(new LatheFullQueueMessage(GetIDQueue())); UserInterface?.SendMessage(new LatheFullQueueMessage(GetIdQueue()));
} }
break; break;
case LatheSyncRequestMessage msg: case LatheSyncRequestMessage _:
if (!Owner.TryGetComponent(out MaterialStorageComponent storage)) return; if (!Owner.HasComponent<MaterialStorageComponent>()) return;
_userInterface.SendMessage(new LatheFullQueueMessage(GetIDQueue())); UserInterface?.SendMessage(new LatheFullQueueMessage(GetIdQueue()));
if (_producingRecipe != null) if (_producingRecipe != null)
_userInterface.SendMessage(new LatheProducingRecipeMessage(_producingRecipe.ID)); UserInterface?.SendMessage(new LatheProducingRecipeMessage(_producingRecipe.ID));
break; break;
case LatheServerSelectionMessage msg: case LatheServerSelectionMessage _:
if (!Owner.TryGetComponent(out ResearchClientComponent researchClient)) return; if (!Owner.TryGetComponent(out ResearchClientComponent? researchClient)) return;
researchClient.OpenUserInterface(message.Session); researchClient.OpenUserInterface(message.Session);
break; break;
case LatheServerSyncMessage msg: case LatheServerSyncMessage _:
if (!Owner.TryGetComponent(out TechnologyDatabaseComponent database) if (!Owner.TryGetComponent(out TechnologyDatabaseComponent? database)
|| !Owner.TryGetComponent(out ProtolatheDatabaseComponent protoDatabase)) return; || !Owner.TryGetComponent(out ProtolatheDatabaseComponent? protoDatabase)) return;
if (database.SyncWithServer()) if (database.SyncWithServer())
protoDatabase.Sync(); protoDatabase.Sync();
@@ -103,9 +108,9 @@ namespace Content.Server.GameObjects.Components.Research
{ {
return false; return false;
} }
if (Producing || !CanProduce(recipe) || !Owner.TryGetComponent(out MaterialStorageComponent storage)) return false; if (Producing || !CanProduce(recipe) || !Owner.TryGetComponent(out MaterialStorageComponent? storage)) return false;
_userInterface.SendMessage(new LatheFullQueueMessage(GetIDQueue())); UserInterface?.SendMessage(new LatheFullQueueMessage(GetIdQueue()));
Producing = true; Producing = true;
_producingRecipe = recipe; _producingRecipe = recipe;
@@ -116,7 +121,7 @@ namespace Content.Server.GameObjects.Components.Research
storage.RemoveMaterial(material, amount); storage.RemoveMaterial(material, amount);
} }
_userInterface.SendMessage(new LatheProducingRecipeMessage(recipe.ID)); UserInterface?.SendMessage(new LatheProducingRecipeMessage(recipe.ID));
State = LatheState.Producing; State = LatheState.Producing;
SetAppearance(LatheVisualState.Producing); SetAppearance(LatheVisualState.Producing);
@@ -126,7 +131,7 @@ namespace Content.Server.GameObjects.Components.Research
Producing = false; Producing = false;
_producingRecipe = null; _producingRecipe = null;
Owner.EntityManager.SpawnEntity(recipe.Result, Owner.Transform.GridPosition); Owner.EntityManager.SpawnEntity(recipe.Result, Owner.Transform.GridPosition);
_userInterface.SendMessage(new LatheStoppedProducingRecipeMessage()); UserInterface?.SendMessage(new LatheStoppedProducingRecipeMessage());
State = LatheState.Base; State = LatheState.Base;
SetAppearance(LatheVisualState.Idle); SetAppearance(LatheVisualState.Idle);
}); });
@@ -136,12 +141,12 @@ namespace Content.Server.GameObjects.Components.Research
public void OpenUserInterface(IPlayerSession session) public void OpenUserInterface(IPlayerSession session)
{ {
_userInterface.Open(session); UserInterface?.Open(session);
} }
void IActivate.Activate(ActivateEventArgs eventArgs) void IActivate.Activate(ActivateEventArgs eventArgs)
{ {
if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) if (!eventArgs.User.TryGetComponent(out IActorComponent? actor))
return; return;
if (!Powered) if (!Powered)
{ {
@@ -153,12 +158,12 @@ namespace Content.Server.GameObjects.Components.Research
async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs) async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
{ {
if (!Owner.TryGetComponent(out MaterialStorageComponent storage) if (!Owner.TryGetComponent(out MaterialStorageComponent? storage)
|| !eventArgs.Using.TryGetComponent(out MaterialComponent material)) return false; || !eventArgs.Using.TryGetComponent(out MaterialComponent? material)) return false;
var multiplier = 1; var multiplier = 1;
if (eventArgs.Using.TryGetComponent(out StackComponent stack)) multiplier = stack.Count; if (eventArgs.Using.TryGetComponent(out StackComponent? stack)) multiplier = stack.Count;
var totalAmount = 0; var totalAmount = 0;
@@ -205,11 +210,13 @@ namespace Content.Server.GameObjects.Components.Research
private void SetAppearance(LatheVisualState state) private void SetAppearance(LatheVisualState state)
{ {
if (_appearance != null || Owner.TryGetComponent(out _appearance)) if (Owner.TryGetComponent(out AppearanceComponent? appearance))
_appearance.SetData(PowerDeviceVisuals.VisualState, state); {
appearance.SetData(PowerDeviceVisuals.VisualState, state);
}
} }
private Queue<string> GetIDQueue() private Queue<string> GetIdQueue()
{ {
var queue = new Queue<string>(); var queue = new Queue<string>();
foreach (var recipePrototype in Queue) foreach (var recipePrototype in Queue)

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.EntitySystems; #nullable enable
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components.Research; using Content.Shared.GameObjects.Components.Research;
using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Interfaces.GameObjects.Components;
using Robust.Server.GameObjects.Components.UserInterface; using Robust.Server.GameObjects.Components.UserInterface;
@@ -14,20 +15,21 @@ namespace Content.Server.GameObjects.Components.Research
[RegisterComponent] [RegisterComponent]
public class ResearchClientComponent : SharedResearchClientComponent, IActivate public class ResearchClientComponent : SharedResearchClientComponent, IActivate
{ {
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
// TODO: Create GUI for changing RD server. // TODO: Create GUI for changing RD server.
private BoundUserInterface? UserInterface =>
private BoundUserInterface _userInterface; Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(ResearchClientUiKey.Key, out var boundUi)
#pragma warning disable 649 ? boundUi
[Dependency] private readonly IEntitySystemManager _entitySystemManager; : null;
#pragma warning restore 649
public bool ConnectedToServer => Server != null; public bool ConnectedToServer => Server != null;
[ViewVariables(VVAccess.ReadOnly)] [ViewVariables(VVAccess.ReadOnly)]
public ResearchServerComponent Server { get; set; } public ResearchServerComponent? Server { get; set; }
public bool RegisterServer(ResearchServerComponent server) public bool RegisterServer(ResearchServerComponent? server)
{ {
var result = server != null && server.RegisterClient(this); var result = server != null && server.RegisterClient(this);
return result; return result;
@@ -41,23 +43,28 @@ namespace Content.Server.GameObjects.Components.Research
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
// For now it just registers on the first server it can find. // For now it just registers on the first server it can find.
var servers = _entitySystemManager.GetEntitySystem<ResearchSystem>().Servers; var servers = _entitySystemManager.GetEntitySystem<ResearchSystem>().Servers;
if(servers.Count > 0)
if (servers.Count > 0)
RegisterServer(servers[0]); RegisterServer(servers[0]);
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(ResearchClientUiKey.Key);
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; if (UserInterface != null)
{
UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
}
} }
public void OpenUserInterface(IPlayerSession session) public void OpenUserInterface(IPlayerSession session)
{ {
UpdateUserInterface(); UpdateUserInterface();
_userInterface.Open(session); UserInterface?.Open(session);
} }
void IActivate.Activate(ActivateEventArgs eventArgs) void IActivate.Activate(ActivateEventArgs eventArgs)
{ {
if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) if (!eventArgs.User.TryGetComponent(out IActorComponent? actor))
return; return;
OpenUserInterface(actor.playerSession); OpenUserInterface(actor.playerSession);
@@ -65,7 +72,7 @@ namespace Content.Server.GameObjects.Components.Research
public void UpdateUserInterface() public void UpdateUserInterface()
{ {
_userInterface?.SetState(GetNewUiState()); UserInterface?.SetState(GetNewUiState());
} }
private ResearchClientBoundInterfaceState GetNewUiState() private ResearchClientBoundInterfaceState GetNewUiState()
@@ -73,7 +80,7 @@ namespace Content.Server.GameObjects.Components.Research
var rd = _entitySystemManager.GetEntitySystem<ResearchSystem>(); var rd = _entitySystemManager.GetEntitySystem<ResearchSystem>();
return new ResearchClientBoundInterfaceState(rd.Servers.Count, rd.GetServerNames(), return new ResearchClientBoundInterfaceState(rd.Servers.Count, rd.GetServerNames(),
rd.GetServerIds(), ConnectedToServer ? Server.Id : -1); rd.GetServerIds(), ConnectedToServer ? Server!.Id : -1);
} }
private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage msg) private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage msg)

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.Components.Power.ApcNetComponents; #nullable enable
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
using Content.Shared.Audio; using Content.Shared.Audio;
using Content.Shared.GameObjects.Components.Research; using Content.Shared.GameObjects.Components.Research;
using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Interfaces.GameObjects.Components;
@@ -14,6 +15,7 @@ using Robust.Shared.Interfaces.Random;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Research namespace Content.Server.GameObjects.Components.Research
{ {
@@ -21,31 +23,38 @@ namespace Content.Server.GameObjects.Components.Research
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
public class ResearchConsoleComponent : SharedResearchConsoleComponent, IActivate public class ResearchConsoleComponent : SharedResearchConsoleComponent, IActivate
{ {
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
#pragma warning disable 649 private const string SoundCollectionName = "keyboard";
[Dependency] private readonly IPrototypeManager _prototypeManager;
[Dependency] private readonly IRobustRandom _random;
#pragma warning restore 649
private BoundUserInterface _userInterface; private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
private ResearchClientComponent _client;
private PowerReceiverComponent _powerReceiver;
private const string _soundCollectionName = "keyboard";
private bool Powered => _powerReceiver.Powered; [ViewVariables]
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(ResearchConsoleUiKey.Key, out var boundUi)
? boundUi
: null;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(ResearchConsoleUiKey.Key);
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; if (UserInterface != null)
_client = Owner.GetComponent<ResearchClientComponent>(); {
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>(); UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
}
Owner.EnsureComponent<ResearchClientComponent>();
} }
private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage message) private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage message)
{ {
if (!Owner.TryGetComponent(out TechnologyDatabaseComponent database)) return; if (!Owner.TryGetComponent(out TechnologyDatabaseComponent? database))
return;
if (!Owner.TryGetComponent(out ResearchClientComponent? client))
return;
if (!Powered) if (!Powered)
return; return;
@@ -54,8 +63,9 @@ namespace Content.Server.GameObjects.Components.Research
case ConsoleUnlockTechnologyMessage msg: case ConsoleUnlockTechnologyMessage msg:
var protoMan = IoCManager.Resolve<IPrototypeManager>(); var protoMan = IoCManager.Resolve<IPrototypeManager>();
if (!protoMan.TryIndex(msg.Id, out TechnologyPrototype tech)) break; if (!protoMan.TryIndex(msg.Id, out TechnologyPrototype tech)) break;
if(!_client.Server.CanUnlockTechnology(tech)) break; if (client.Server == null) break;
if (_client.Server.UnlockTechnology(tech)) if (!client.Server.CanUnlockTechnology(tech)) break;
if (client.Server.UnlockTechnology(tech))
{ {
database.SyncWithServer(); database.SyncWithServer();
database.Dirty(); database.Dirty();
@@ -64,13 +74,12 @@ namespace Content.Server.GameObjects.Components.Research
break; break;
case ConsoleServerSyncMessage msg: case ConsoleServerSyncMessage _:
database.SyncWithServer(); database.SyncWithServer();
UpdateUserInterface(); UpdateUserInterface();
break; break;
case ConsoleServerSelectionMessage msg: case ConsoleServerSelectionMessage _:
if (!Owner.TryGetComponent(out ResearchClientComponent client)) break;
client.OpenUserInterface(message.Session); client.OpenUserInterface(message.Session);
break; break;
} }
@@ -81,13 +90,17 @@ namespace Content.Server.GameObjects.Components.Research
/// </summary> /// </summary>
public void UpdateUserInterface() public void UpdateUserInterface()
{ {
_userInterface.SetState(GetNewUiState()); UserInterface?.SetState(GetNewUiState());
} }
private ResearchConsoleBoundInterfaceState GetNewUiState() private ResearchConsoleBoundInterfaceState GetNewUiState()
{ {
var points = _client.ConnectedToServer ? _client.Server.Point : 0; if (!Owner.TryGetComponent(out ResearchClientComponent? client) ||
var pointsPerSecond = _client.ConnectedToServer ? _client.Server.PointsPerSecond : 0; client.Server == null)
return new ResearchConsoleBoundInterfaceState(default, default);
var points = client.ConnectedToServer ? client.Server.Point : 0;
var pointsPerSecond = client.ConnectedToServer ? client.Server.PointsPerSecond : 0;
return new ResearchConsoleBoundInterfaceState(points, pointsPerSecond); return new ResearchConsoleBoundInterfaceState(points, pointsPerSecond);
} }
@@ -98,12 +111,12 @@ namespace Content.Server.GameObjects.Components.Research
/// <param name="session">Session where the UI will be shown</param> /// <param name="session">Session where the UI will be shown</param>
public void OpenUserInterface(IPlayerSession session) public void OpenUserInterface(IPlayerSession session)
{ {
_userInterface.Open(session); UserInterface?.Open(session);
} }
void IActivate.Activate(ActivateEventArgs eventArgs) void IActivate.Activate(ActivateEventArgs eventArgs)
{ {
if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) if (!eventArgs.User.TryGetComponent(out IActorComponent? actor))
return; return;
if (!Powered) if (!Powered)
{ {
@@ -112,17 +125,14 @@ namespace Content.Server.GameObjects.Components.Research
OpenUserInterface(actor.playerSession); OpenUserInterface(actor.playerSession);
PlayKeyboardSound(); PlayKeyboardSound();
return;
} }
private void PlayKeyboardSound() private void PlayKeyboardSound()
{ {
var soundCollection = _prototypeManager.Index<SoundCollectionPrototype>(_soundCollectionName); var soundCollection = _prototypeManager.Index<SoundCollectionPrototype>(SoundCollectionName);
var file = _random.Pick(soundCollection.PickFiles); var file = _random.Pick(soundCollection.PickFiles);
var audioSystem = EntitySystem.Get<AudioSystem>(); var audioSystem = EntitySystem.Get<AudioSystem>();
audioSystem.PlayFromEntity(file,Owner,AudioParams.Default); audioSystem.PlayFromEntity(file,Owner,AudioParams.Default);
} }
} }
} }

View File

@@ -73,7 +73,7 @@ namespace Content.Server.GameObjects.Components.Research
base.Initialize(); base.Initialize();
Id = ServerCount++; Id = ServerCount++;
EntitySystem.Get<ResearchSystem>()?.RegisterServer(this); EntitySystem.Get<ResearchSystem>()?.RegisterServer(this);
Database = Owner.GetComponent<TechnologyDatabaseComponent>(); Database = Owner.EnsureComponent<TechnologyDatabaseComponent>();
Owner.TryGetComponent(out _powerReceiver); Owner.TryGetComponent(out _powerReceiver);
} }

View File

@@ -14,9 +14,7 @@ namespace Content.Server.GameObjects.Components.Rotatable
[RegisterComponent] [RegisterComponent]
public class FlippableComponent : Component public class FlippableComponent : Component
{ {
#pragma warning disable 649
[Dependency] private readonly IServerNotifyManager _notifyManager = default!; [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
#pragma warning restore 649
public override string Name => "Flippable"; public override string Name => "Flippable";

View File

@@ -1,8 +1,8 @@
using System; #nullable enable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Content.Server.GameObjects.Components.Power.ApcNetComponents; using Content.Server.GameObjects.Components.Power.ApcNetComponents;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components.VendingMachines; using Content.Shared.GameObjects.Components.VendingMachines;
using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Interfaces.GameObjects.Components;
@@ -29,27 +29,28 @@ namespace Content.Server.GameObjects.Components.VendingMachines
[ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IActivate))]
public class VendingMachineComponent : SharedVendingMachineComponent, IActivate, IExamine, IBreakAct, IWires public class VendingMachineComponent : SharedVendingMachineComponent, IActivate, IExamine, IBreakAct, IWires
{ {
#pragma warning disable 649 [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IRobustRandom _random;
#pragma warning restore 649
private AppearanceComponent _appearance;
private BoundUserInterface _userInterface;
private PowerReceiverComponent _powerReceiver;
private bool _ejecting = false; private bool _ejecting;
private TimeSpan _animationDuration = TimeSpan.Zero; private TimeSpan _animationDuration = TimeSpan.Zero;
private string _packPrototypeId; private string _packPrototypeId = "";
private string _description; private string? _description;
private string _spriteName; private string _spriteName = "";
private bool Powered => _powerReceiver.Powered; private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
private bool _broken = false; private bool _broken;
private string _soundVend; private string _soundVend = "";
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(VendingMachineUiKey.Key, out var boundUi)
? boundUi
: null;
public void Activate(ActivateEventArgs eventArgs) public void Activate(ActivateEventArgs eventArgs)
{ {
if(!eventArgs.User.TryGetComponent(out IActorComponent actor)) if(!eventArgs.User.TryGetComponent(out IActorComponent? actor))
{ {
return; return;
} }
@@ -62,7 +63,7 @@ namespace Content.Server.GameObjects.Components.VendingMachines
wires.OpenInterface(actor.playerSession); wires.OpenInterface(actor.playerSession);
} else } else
{ {
_userInterface.Open(actor.playerSession); UserInterface?.Open(actor.playerSession);
} }
} }
@@ -106,25 +107,32 @@ namespace Content.Server.GameObjects.Components.VendingMachines
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_appearance = Owner.GetComponent<AppearanceComponent>();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>() if (UserInterface != null)
.GetBoundUserInterface(VendingMachineUiKey.Key); {
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>(); }
_powerReceiver.OnPowerStateChanged += UpdatePower;
TrySetVisualState(_powerReceiver.Powered ? VendingMachineVisualState.Normal : VendingMachineVisualState.Off); if (Owner.TryGetComponent(out PowerReceiverComponent? receiver))
{
receiver.OnPowerStateChanged += UpdatePower;
TrySetVisualState(receiver.Powered ? VendingMachineVisualState.Normal : VendingMachineVisualState.Off);
}
InitializeFromPrototype(); InitializeFromPrototype();
} }
public override void OnRemove() public override void OnRemove()
{ {
_appearance = null; if (Owner.TryGetComponent(out PowerReceiverComponent? receiver))
_powerReceiver.OnPowerStateChanged -= UpdatePower; {
_powerReceiver = null; receiver.OnPowerStateChanged -= UpdatePower;
}
base.OnRemove(); base.OnRemove();
} }
private void UpdatePower(object sender, PowerStateEventArgs args) private void UpdatePower(object? sender, PowerStateEventArgs args)
{ {
var state = args.Powered ? VendingMachineVisualState.Normal : VendingMachineVisualState.Off; var state = args.Powered ? VendingMachineVisualState.Normal : VendingMachineVisualState.Off;
TrySetVisualState(state); TrySetVisualState(state);
@@ -141,8 +149,8 @@ namespace Content.Server.GameObjects.Components.VendingMachines
case VendingMachineEjectMessage msg: case VendingMachineEjectMessage msg:
TryEject(msg.ID); TryEject(msg.ID);
break; break;
case InventorySyncRequestMessage msg: case InventorySyncRequestMessage _:
_userInterface.SendMessage(new VendingMachineInventoryMessage(Inventory)); UserInterface?.SendMessage(new VendingMachineInventoryMessage(Inventory));
break; break;
} }
} }
@@ -160,7 +168,7 @@ namespace Content.Server.GameObjects.Components.VendingMachines
return; return;
} }
VendingMachineInventoryEntry entry = Inventory.Find(x => x.ID == id); var entry = Inventory.Find(x => x.ID == id);
if (entry == null) if (entry == null)
{ {
FlickDenyAnimation(); FlickDenyAnimation();
@@ -175,7 +183,7 @@ namespace Content.Server.GameObjects.Components.VendingMachines
_ejecting = true; _ejecting = true;
entry.Amount--; entry.Amount--;
_userInterface.SendMessage(new VendingMachineInventoryMessage(Inventory)); UserInterface?.SendMessage(new VendingMachineInventoryMessage(Inventory));
TrySetVisualState(VendingMachineVisualState.Eject); TrySetVisualState(VendingMachineVisualState.Eject);
Timer.Spawn(_animationDuration, () => Timer.Spawn(_animationDuration, () =>
@@ -204,14 +212,20 @@ namespace Content.Server.GameObjects.Components.VendingMachines
if (_broken) if (_broken)
{ {
finalState = VendingMachineVisualState.Broken; finalState = VendingMachineVisualState.Broken;
} else if (_ejecting) }
else if (_ejecting)
{ {
finalState = VendingMachineVisualState.Eject; finalState = VendingMachineVisualState.Eject;
} else if (!Powered) }
else if (!Powered)
{ {
finalState = VendingMachineVisualState.Off; finalState = VendingMachineVisualState.Off;
} }
_appearance.SetData(VendingMachineVisuals.VisualState, finalState);
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
{
appearance.SetData(VendingMachineVisuals.VisualState, finalState);
}
} }
public void OnBreak(BreakageEventArgs eventArgs) public void OnBreak(BreakageEventArgs eventArgs)

View File

@@ -158,7 +158,8 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
{ {
base.OnAdd(); base.OnAdd();
var rangedWeaponComponent = Owner.GetComponent<ServerRangedWeaponComponent>(); var rangedWeaponComponent = Owner.GetComponent<ServerRangedWeaponComponent>();
rangedWeaponComponent.Barrel = this;
rangedWeaponComponent.Barrel ??= this;
rangedWeaponComponent.FireHandler += Fire; rangedWeaponComponent.FireHandler += Fire;
rangedWeaponComponent.WeaponCanFireHandler += WeaponCanFire; rangedWeaponComponent.WeaponCanFireHandler += WeaponCanFire;
} }

View File

@@ -33,13 +33,11 @@ namespace Content.Server.GameObjects.Components
[RegisterComponent] [RegisterComponent]
public class WiresComponent : SharedWiresComponent, IInteractUsing, IExamine, IMapInit public class WiresComponent : SharedWiresComponent, IInteractUsing, IExamine, IMapInit
{ {
#pragma warning disable 649
[Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IServerNotifyManager _notifyManager = default!; [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
#pragma warning restore 649
private AudioSystem _audioSystem = default!; private AudioSystem _audioSystem = default!;
private AppearanceComponent _appearance = default!; private AppearanceComponent _appearance = default!;
private BoundUserInterface _userInterface = default!;
private bool _isPanelOpen; private bool _isPanelOpen;
@@ -140,15 +138,23 @@ namespace Content.Server.GameObjects.Components
[ViewVariables] [ViewVariables]
private string? _layoutId; private string? _layoutId;
private BoundUserInterface? UserInterface =>
Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) &&
ui.TryGetBoundUserInterface(WiresUiKey.Key, out var boundUi)
? boundUi
: null;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_audioSystem = EntitySystem.Get<AudioSystem>(); _audioSystem = EntitySystem.Get<AudioSystem>();
_appearance = Owner.GetComponent<AppearanceComponent>(); _appearance = Owner.GetComponent<AppearanceComponent>();
_appearance.SetData(WiresVisuals.MaintenancePanelState, IsPanelOpen); _appearance.SetData(WiresVisuals.MaintenancePanelState, IsPanelOpen);
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(WiresUiKey.Key); if (UserInterface != null)
_userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; {
UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
}
} }
private void GenerateSerialNumber() private void GenerateSerialNumber()
@@ -357,7 +363,7 @@ namespace Content.Server.GameObjects.Components
/// </summary> /// </summary>
public void OpenInterface(IPlayerSession session) public void OpenInterface(IPlayerSession session)
{ {
_userInterface.Open(session); UserInterface?.Open(session);
} }
private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg) private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg)
@@ -450,7 +456,7 @@ namespace Content.Server.GameObjects.Components
entry.Letter)); entry.Letter));
} }
_userInterface.SetState( UserInterface?.SetState(
new WiresBoundUserInterfaceState( new WiresBoundUserInterfaceState(
clientList.ToArray(), clientList.ToArray(),
_statuses.Select(p => new StatusEntry(p.Key, p.Value)).ToArray(), _statuses.Select(p => new StatusEntry(p.Key, p.Value)).ToArray(),

View File

@@ -87,7 +87,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI
/// <param name="controller"></param> /// <param name="controller"></param>
public void ProcessorInitialize(AiControllerComponent controller) public void ProcessorInitialize(AiControllerComponent controller)
{ {
if (controller.Processor != null) return; if (controller.Processor != null || controller.LogicName == null) return;
controller.Processor = CreateProcessor(controller.LogicName); controller.Processor = CreateProcessor(controller.LogicName);
controller.Processor.SelfEntity = controller.Owner; controller.Processor.SelfEntity = controller.Owner;
controller.Processor.Setup(); controller.Processor.Setup();

View File

@@ -153,13 +153,20 @@ namespace Content.Server.GameObjects.EntitySystems.Atmos
private bool TryRefreshTile(GridAtmosphereComponent gam, GasOverlayData oldTile, MapIndices indices, out GasOverlayData overlayData) private bool TryRefreshTile(GridAtmosphereComponent gam, GasOverlayData oldTile, MapIndices indices, out GasOverlayData overlayData)
{ {
var tile = gam.GetTile(indices); var tile = gam.GetTile(indices);
if (tile == null)
{
overlayData = default;
return false;
}
var tileData = new List<GasData>(); var tileData = new List<GasData>();
for (byte i = 0; i < Atmospherics.TotalNumberOfGases; i++) for (byte i = 0; i < Atmospherics.TotalNumberOfGases; i++)
{ {
var gas = Atmospherics.GetGas(i); var gas = Atmospherics.GetGas(i);
var overlay = Atmospherics.GetOverlay(i); var overlay = Atmospherics.GetOverlay(i);
if (overlay == null || tile.Air == null) continue; if (overlay == null || tile?.Air == null) continue;
var moles = tile.Air.Gases[i]; var moles = tile.Air.Gases[i];
@@ -169,7 +176,7 @@ namespace Content.Server.GameObjects.EntitySystems.Atmos
tileData.Add(data); tileData.Add(data);
} }
overlayData = new GasOverlayData(tile.Hotspot.State, tile.Hotspot.Temperature, tileData.Count == 0 ? null : tileData.ToArray()); overlayData = new GasOverlayData(tile!.Hotspot.State, tile.Hotspot.Temperature, tileData.Count == 0 ? null : tileData.ToArray());
if (overlayData.Equals(oldTile)) if (overlayData.Equals(oldTile))
{ {

View File

@@ -30,13 +30,11 @@ namespace Content.Server.GameObjects.EntitySystems
[UsedImplicitly] [UsedImplicitly]
internal class MoverSystem : SharedMoverSystem internal class MoverSystem : SharedMoverSystem
{ {
#pragma warning disable 649
[Dependency] private readonly IPauseManager _pauseManager = default!; [Dependency] private readonly IPauseManager _pauseManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!; [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!;
[Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!; [Dependency] private readonly IRobustRandom _robustRandom = default!;
#pragma warning restore 649
private AudioSystem _audioSystem = default!; private AudioSystem _audioSystem = default!;

View File

@@ -21,9 +21,7 @@ namespace Content.Shared.GameObjects.Components.Damage
[ComponentReference(typeof(IDamageableComponent))] [ComponentReference(typeof(IDamageableComponent))]
public class DamageableComponent : Component, IDamageableComponent public class DamageableComponent : Component, IDamageableComponent
{ {
#pragma warning disable 649
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
#pragma warning restore 649
public override string Name => "Damageable"; public override string Name => "Damageable";

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Content.Shared.GameObjects.Components.Mobs; using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Physics; using Content.Shared.Physics;
@@ -7,6 +8,7 @@ using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components; using Robust.Shared.GameObjects.Components;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Physics;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
@@ -116,12 +118,18 @@ namespace Content.Shared.GameObjects.Components.Movement
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
var collidable = Owner.GetComponent<ICollidableComponent>();
var collidable = Owner.EnsureComponent<CollidableComponent>();
collidable.Hard = false; collidable.Hard = false;
var shape = collidable.PhysicsShapes[0];
var shape = collidable.PhysicsShapes.FirstOrDefault();
if (shape != null)
{
shape.CollisionLayer |= (int) CollisionGroup.SmallImpassable; shape.CollisionLayer |= (int) CollisionGroup.SmallImpassable;
shape.CollisionMask = (int)CollisionGroup.None; shape.CollisionMask = (int) CollisionGroup.None;
}
} }
public override void ExposeData(ObjectSerializer serializer) public override void ExposeData(ObjectSerializer serializer)

View File

@@ -66,6 +66,7 @@
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue">&lt;data&gt;&lt;IncludeFilters /&gt;&lt;ExcludeFilters&gt;&lt;Filter ModuleMask="Lidgren.Network" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /&gt;&lt;/ExcludeFilters&gt;&lt;/data&gt;</s:String> <s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue">&lt;data&gt;&lt;IncludeFilters /&gt;&lt;ExcludeFilters&gt;&lt;Filter ModuleMask="Lidgren.Network" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /&gt;&lt;/ExcludeFilters&gt;&lt;/data&gt;</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Collidable/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Collidable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Cooldowns/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Cooldowns/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Discharger/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=crit/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=crit/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=firelocks/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=firelocks/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=diminishingly/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=diminishingly/@EntryIndexedValue">True</s:Boolean>