diff --git a/Content.Client/GameObjects/Components/Body/BodyManagerComponent.cs b/Content.Client/GameObjects/Components/Body/BodyManagerComponent.cs index 61049ec7a0..767f354f4b 100644 --- a/Content.Client/GameObjects/Components/Body/BodyManagerComponent.cs +++ b/Content.Client/GameObjects/Components/Body/BodyManagerComponent.cs @@ -17,9 +17,7 @@ namespace Content.Client.GameObjects.Components.Body [ComponentReference(typeof(IBodyManagerComponent))] public class BodyManagerComponent : SharedBodyManagerComponent, IClientDraggable { -#pragma warning disable 649 [Dependency] private readonly IEntityManager _entityManager = default!; -#pragma warning restore 649 public bool ClientCanDropOn(CanDropEventArgs eventArgs) { diff --git a/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs b/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs index eeae34cbde..ab86148401 100644 --- a/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs +++ b/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs @@ -27,13 +27,9 @@ namespace Content.Client.GameObjects.Components.Instruments /// public event Action? OnMidiPlaybackEnded; -#pragma warning disable 649 [Dependency] private readonly IMidiManager _midiManager = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly IClientNetManager _netManager = default!; -#pragma warning restore 649 private IMidiRenderer? _renderer; diff --git a/Content.Client/GameObjects/Components/Items/HandsComponent.cs b/Content.Client/GameObjects/Components/Items/HandsComponent.cs index 30e32afad3..f023c467ee 100644 --- a/Content.Client/GameObjects/Components/Items/HandsComponent.cs +++ b/Content.Client/GameObjects/Components/Items/HandsComponent.cs @@ -19,9 +19,7 @@ namespace Content.Client.GameObjects.Components.Items { private HandsGui? _gui; -#pragma warning disable 649 [Dependency] private readonly IGameHud _gameHud = default!; -#pragma warning restore 649 /// private readonly List _hands = new List(); diff --git a/Content.IntegrationTests/Tests/Doors/AirlockTest.cs b/Content.IntegrationTests/Tests/Doors/AirlockTest.cs index bcf10f7940..939ebce941 100644 --- a/Content.IntegrationTests/Tests/Doors/AirlockTest.cs +++ b/Content.IntegrationTests/Tests/Doors/AirlockTest.cs @@ -1,16 +1,11 @@ -using System.IO; -using System.Threading.Tasks; +using System.Threading.Tasks; using Content.Server.GameObjects.Components.Doors; -using Content.Shared.Physics; using NUnit.Framework; -using Robust.Server.Console.Commands; using Robust.Shared.GameObjects.Components; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; -using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Physics; -using Robust.Shared.Prototypes; using static Content.Server.GameObjects.Components.Doors.ServerDoorComponent; namespace Content.IntegrationTests.Tests.Doors diff --git a/Content.IntegrationTests/Tests/EntityTest.cs b/Content.IntegrationTests/Tests/EntityTest.cs index 639a2f78b6..4fd9846263 100644 --- a/Content.IntegrationTests/Tests/EntityTest.cs +++ b/Content.IntegrationTests/Tests/EntityTest.cs @@ -1,5 +1,8 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.IO; +using System.Linq; using System.Threading.Tasks; using NUnit.Framework; using Robust.Server.Interfaces.Maps; @@ -11,6 +14,7 @@ using Robust.Shared.Log; using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Prototypes; +using Logger = Robust.Shared.Log.Logger; namespace Content.IntegrationTests.Tests { @@ -30,7 +34,7 @@ namespace Content.IntegrationTests.Tests var pauseMan = server.ResolveDependency(); var prototypes = new List(); IMapGrid grid = default; - IEntity testEntity = null; + IEntity testEntity; //Build up test environment server.Post(() => @@ -59,7 +63,7 @@ namespace Content.IntegrationTests.Tests { try { - Logger.LogS(LogLevel.Debug, "EntityTest", "Testing: " + prototype.ID); + Logger.LogS(LogLevel.Debug, "EntityTest", $"Testing: {prototype.ID}"); testEntity = entityMan.SpawnEntity(prototype.ID, testLocation); server.RunTicks(2); Assert.That(testEntity.Initialized); @@ -69,8 +73,8 @@ namespace Content.IntegrationTests.Tests //Fail any exceptions thrown on spawn catch (Exception e) { - Logger.LogS(LogLevel.Error, "EntityTest", "Entity '" + prototype.ID + "' threw: " + e.Message); - //Assert.Fail(); + Logger.LogS(LogLevel.Error, "EntityTest", $"Entity '{prototype.ID}' threw: {e.Message}"); + Assert.Fail(); throw; } } @@ -101,5 +105,125 @@ namespace Content.IntegrationTests.Tests 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(); + var entityManager = server.ResolveDependency(); + var mapLoader = server.ResolveDependency(); + var pauseManager = server.ResolveDependency(); + var componentFactory = server.ResolveDependency(); + var prototypeManager = server.ResolveDependency(); + + 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 components, List references)> + { + (new List(), new List()) + }; + + // 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(), new List())); + } + + 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(); + } } } diff --git a/Content.IntegrationTests/Tests/PowerTest.cs b/Content.IntegrationTests/Tests/PowerTest.cs index b53fa69734..5b41142b7d 100644 --- a/Content.IntegrationTests/Tests/PowerTest.cs +++ b/Content.IntegrationTests/Tests/PowerTest.cs @@ -49,7 +49,7 @@ namespace Content.IntegrationTests.Tests }); server.RunTicks(1); //let run a tick for PowerNet to process power - + server.Assert(() => { Assert.That(consumer1.DrawRate, Is.EqualTo(consumer1.ReceivedPower)); //first should be fully powered @@ -127,6 +127,7 @@ namespace Content.IntegrationTests.Tests Assert.That(apcEnt.TryGetComponent(out var apc)); Assert.That(apcExtensionEnt.TryGetComponent(out var provider)); Assert.That(powerReceiverEnt.TryGetComponent(out receiver)); + Assert.NotNull(apc.Battery); provider.PowerTransferRange = 5; //arbitrary range to reach receiver receiver.PowerReceptionRange = 5; //arbitrary range to reach provider diff --git a/Content.Server/Atmos/GasSprayerComponent.cs b/Content.Server/Atmos/GasSprayerComponent.cs index 4b78d413a9..d414ce1714 100644 --- a/Content.Server/Atmos/GasSprayerComponent.cs +++ b/Content.Server/Atmos/GasSprayerComponent.cs @@ -20,10 +20,8 @@ namespace Content.Server.Atmos [RegisterComponent] public class GasSprayerComponent : Component, IAfterInteract { -#pragma warning disable 649 [Dependency] private readonly IServerNotifyManager _notifyManager = 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 public override string Name => "GasSprayer"; diff --git a/Content.Server/GameObjects/Components/Access/IdCardConsoleComponent.cs b/Content.Server/GameObjects/Components/Access/IdCardConsoleComponent.cs index 841b4dd176..9fa417bc1a 100644 --- a/Content.Server/GameObjects/Components/Access/IdCardConsoleComponent.cs +++ b/Content.Server/GameObjects/Components/Access/IdCardConsoleComponent.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +#nullable enable +using System.Collections.Generic; using System.Linq; using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.Interfaces; @@ -15,6 +16,7 @@ using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Log; using Robust.Shared.Prototypes; +using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Access { @@ -22,16 +24,19 @@ namespace Content.Server.GameObjects.Components.Access [ComponentReference(typeof(IActivate))] public class IdCardConsoleComponent : SharedIdCardConsoleComponent, IActivate { -#pragma warning disable 649 - [Dependency] private readonly IServerNotifyManager _notifyManager; - [Dependency] private readonly ILocalizationManager _localizationManager; - [Dependency] private readonly IPrototypeManager _prototypeManager; -#pragma warning restore 649 + [Dependency] private readonly IServerNotifyManager _notifyManager = default!; + [Dependency] private readonly ILocalizationManager _localizationManager = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - private BoundUserInterface _userInterface; - private ContainerSlot _privilegedIdContainer; - private ContainerSlot _targetIdContainer; - private AccessReader _accessReader; + private ContainerSlot _privilegedIdContainer = default!; + private ContainerSlot _targetIdContainer = default!; + + [ViewVariables] + private BoundUserInterface? UserInterface => + Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) && + ui.TryGetBoundUserInterface(IdCardConsoleUiKey.Key, out var boundUi) + ? boundUi + : null; public override void Initialize() { @@ -40,16 +45,30 @@ namespace Content.Server.GameObjects.Components.Access _privilegedIdContainer = ContainerManagerComponent.Ensure($"{Name}-privilegedId", Owner); _targetIdContainer = ContainerManagerComponent.Ensure($"{Name}-targetId", Owner); - _accessReader = Owner.GetComponent(); + 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() - .GetBoundUserInterface(IdCardConsoleUiKey.Key); - _userInterface.OnReceiveMessage += OnUiReceiveMessage; UpdateUserInterface(); } private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj) { + if (obj.Session.AttachedEntity == null) + { + return; + } + switch (obj.Message) { case IdButtonPressedMessage msg: @@ -72,13 +91,19 @@ namespace Content.Server.GameObjects.Components.Access } /// - /// Returns true if there is an ID in and said ID satisfies the requirements of . + /// Returns true if there is an ID in and said ID satisfies the requirements of . /// private bool PrivilegedIdIsAuthorized() { + if (!Owner.TryGetComponent(out AccessReader? reader)) + { + return true; + } + var privilegedIdEntity = _privilegedIdContainer.ContainedEntity; - return privilegedIdEntity != null && _accessReader.IsAllowed(privilegedIdEntity); + return privilegedIdEntity != null && reader.IsAllowed(privilegedIdEntity); } + /// /// Called when the "Submit" button in the UI gets pressed. /// Writes data passed from the UI into the ID stored in , if present. @@ -110,7 +135,7 @@ namespace Content.Server.GameObjects.Components.Access /// 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.")); return; @@ -133,7 +158,13 @@ namespace Content.Server.GameObjects.Components.Access { 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!")); return; @@ -185,17 +216,17 @@ namespace Content.Server.GameObjects.Components.Access _privilegedIdContainer.ContainedEntity?.Name ?? "", _targetIdContainer.ContainedEntity?.Name ?? ""); } - _userInterface.SetState(newState); + UserInterface?.SetState(newState); } public void Activate(ActivateEventArgs eventArgs) { - if(!eventArgs.User.TryGetComponent(out IActorComponent actor)) + if(!eventArgs.User.TryGetComponent(out IActorComponent? actor)) { return; } - _userInterface.Open(actor.playerSession); + UserInterface?.Open(actor.playerSession); } } } diff --git a/Content.Server/GameObjects/Components/Atmos/AirtightComponent.cs b/Content.Server/GameObjects/Components/Atmos/AirtightComponent.cs index 07c6ed66e9..5e50bd0c64 100644 --- a/Content.Server/GameObjects/Components/Atmos/AirtightComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/AirtightComponent.cs @@ -1,9 +1,10 @@ -using System; +#nullable enable using Content.Server.GameObjects.EntitySystems; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components.Transform; using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Log; using Robust.Shared.Map; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -13,7 +14,6 @@ namespace Content.Server.GameObjects.Components.Atmos [RegisterComponent] public class AirtightComponent : Component, IMapInit { - private SnapGridComponent _snapGrid; private (GridId, MapIndices) _lastPosition; public override string Name => "Airtight"; @@ -28,7 +28,11 @@ namespace Content.Server.GameObjects.Components.Atmos set { _airBlocked = value; - EntitySystem.Get().GetGridAtmosphere(Owner.Transform.GridID)?.Invalidate(_snapGrid.Position); + + if (Owner.TryGetComponent(out SnapGridComponent? snapGrid)) + { + EntitySystem.Get().GetGridAtmosphere(Owner.Transform.GridID)?.Invalidate(snapGrid.Position); + } } } @@ -48,19 +52,23 @@ namespace Content.Server.GameObjects.Components.Atmos base.Initialize(); // 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 - // down than the object magically not being airtight, so throw one if the SnapGrid component + // 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 log one if the SnapGrid component // is missing. - if (!Owner.TryGetComponent(out _snapGrid)) - throw new Exception("Airtight entities must have a SnapGrid component"); + if (!Owner.EnsureComponent(out SnapGridComponent _)) + Logger.Warning($"Entity {Owner} at {Owner.Transform.MapPosition.ToString()} doesn't have a {nameof(SnapGridComponent)}"); UpdatePosition(); } public void MapInit() { - _snapGrid.OnPositionChanged += OnTransformMove; - _lastPosition = (Owner.Transform.GridID, _snapGrid.Position); + if (Owner.TryGetComponent(out SnapGridComponent? snapGrid)) + { + snapGrid.OnPositionChanged += OnTransformMove; + _lastPosition = (Owner.Transform.GridID, snapGrid.Position); + } + UpdatePosition(); } @@ -70,11 +78,15 @@ namespace Content.Server.GameObjects.Components.Atmos _airBlocked = false; - _snapGrid.OnPositionChanged -= OnTransformMove; + if (Owner.TryGetComponent(out SnapGridComponent? snapGrid)) + { + snapGrid.OnPositionChanged -= OnTransformMove; + + if (_fixVacuum) + EntitySystem.Get().GetGridAtmosphere(Owner.Transform.GridID)? + .FixVacuum(snapGrid.Position); + } - if(_fixVacuum) - EntitySystem.Get().GetGridAtmosphere(Owner.Transform.GridID)? - .FixVacuum(_snapGrid.Position); UpdatePosition(); } @@ -83,15 +95,24 @@ namespace Content.Server.GameObjects.Components.Atmos { UpdatePosition(_lastPosition.Item1, _lastPosition.Item2); 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) { EntitySystem.Get().GetGridAtmosphere(gridId)?.Invalidate(pos); } - } } diff --git a/Content.Server/GameObjects/Components/Atmos/GasAnalyzerComponent.cs b/Content.Server/GameObjects/Components/Atmos/GasAnalyzerComponent.cs index 2a6a2be135..511b26df1c 100644 --- a/Content.Server/GameObjects/Components/Atmos/GasAnalyzerComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/GasAnalyzerComponent.cs @@ -16,30 +16,37 @@ using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Map; +using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Atmos { [RegisterComponent] public class GasAnalyzerComponent : SharedGasAnalyzerComponent, IAfterInteract, IDropped, IUse { -#pragma warning disable 649 - [Dependency] private IServerNotifyManager _notifyManager = default!; - [Dependency] private IMapManager _mapManager = default!; -#pragma warning restore 649 + [Dependency] private readonly IServerNotifyManager _notifyManager = default!; + [Dependency] private readonly IMapManager _mapManager = default!; - private BoundUserInterface _userInterface = default!; private GasAnalyzerDanger _pressureDanger; private float _timeSinceSync; private const float TimeBetweenSyncs = 2f; private bool _checkPlayer = false; // Check at the player pos or at some other tile? 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() { base.Initialize(); - _userInterface = Owner.GetComponent() - .GetBoundUserInterface(GasAnalyzerUiKey.Key); - _userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; + + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; + } } public override ComponentState GetComponentState() @@ -56,7 +63,7 @@ namespace Content.Server.GameObjects.Components.Atmos { _checkPlayer = true; _position = null; - _userInterface.Open(session); + UserInterface?.Open(session); UpdateUserInterface(); Resync(); } @@ -71,7 +78,7 @@ namespace Content.Server.GameObjects.Components.Atmos { _checkPlayer = false; _position = pos; - _userInterface.Open(session); + UserInterface?.Open(session); UpdateUserInterface(); Resync(); } @@ -79,7 +86,7 @@ namespace Content.Server.GameObjects.Components.Atmos public void CloseInterface(IPlayerSession session) { _position = null; - _userInterface.Close(session); + UserInterface?.Close(session); Resync(); } @@ -123,10 +130,15 @@ namespace Content.Server.GameObjects.Components.Atmos private void UpdateUserInterface() { + if (UserInterface == null) + { + return; + } + string? error = null; // 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) return; @@ -156,7 +168,7 @@ namespace Content.Server.GameObjects.Components.Atmos if (tile == null) { error = "No Atmosphere!"; - _userInterface.SetState( + UserInterface.SetState( new GasAnalyzerBoundUserInterfaceState( 0, 0, @@ -166,7 +178,7 @@ namespace Content.Server.GameObjects.Components.Atmos } var gases = new List(); - for (int i = 0; i < Atmospherics.TotalNumberOfGases; i++) + for (var i = 0; i < Atmospherics.TotalNumberOfGases; 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)); } - _userInterface.SetState( + UserInterface.SetState( new GasAnalyzerBoundUserInterfaceState( tile.Pressure, tile.Temperature, diff --git a/Content.Server/GameObjects/Components/Atmos/GasMixtureComponent.cs b/Content.Server/GameObjects/Components/Atmos/GasMixtureHolderComponent.cs similarity index 60% rename from Content.Server/GameObjects/Components/Atmos/GasMixtureComponent.cs rename to Content.Server/GameObjects/Components/Atmos/GasMixtureHolderComponent.cs index c60ad08efa..5aeaff4fc9 100644 --- a/Content.Server/GameObjects/Components/Atmos/GasMixtureComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/GasMixtureHolderComponent.cs @@ -6,16 +6,21 @@ using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Atmos { [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(); public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); - serializer.DataField(this, x => GasMixture.Volume, "volume", 0f); + + serializer.DataReadWriteFunction( + "volume", + 0f, + vol => GasMixture.Volume = vol, + () => GasMixture.Volume); } } } diff --git a/Content.Server/GameObjects/Components/Atmos/GridAtmosphereComponent.cs b/Content.Server/GameObjects/Components/Atmos/GridAtmosphereComponent.cs index 05ba999b0b..6af07c6eba 100644 --- a/Content.Server/GameObjects/Components/Atmos/GridAtmosphereComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/GridAtmosphereComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -50,7 +51,6 @@ namespace Content.Server.GameObjects.Components.Atmos private float _timer = 0f; private Stopwatch _stopwatch = new Stopwatch(); public int UpdateCounter { get; private set; } = 0; - private IMapGrid _grid; [ViewVariables] private readonly HashSet _excitedGroups = new HashSet(1000); @@ -89,42 +89,40 @@ namespace Content.Server.GameObjects.Components.Atmos /// public void PryTile(MapIndices indices) { + if (!Owner.TryGetComponent(out IMapGridComponent? mapGridComponent)) 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(); var tileDef = (ContentTileDefinition)tileDefinitionManager[tile.TypeId]; 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. - var tileItem = IoCManager.Resolve().SpawnEntity(tileDef.ItemDropPrototypeName, new GridCoordinates(indices.X, indices.Y, _grid)); + var tileItem = IoCManager.Resolve().SpawnEntity(tileDef.ItemDropPrototypeName, new GridCoordinates(indices.X, indices.Y, mapGrid)); tileItem.Transform.WorldPosition += (0.2f, 0.2f); } public override void Initialize() { base.Initialize(); - - _grid = Owner.GetComponent().Grid; - RepopulateTiles(); } public override void OnAdd() { base.OnAdd(); - - _grid = Owner.GetComponent().Grid; - 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)) _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() { + if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return; + foreach (var indices in _invalidatedCoords.ToArray()) { var tile = GetTile(indices); @@ -152,7 +152,7 @@ namespace Content.Server.GameObjects.Components.Atmos 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; } @@ -199,8 +199,9 @@ namespace Content.Server.GameObjects.Components.Atmos /// public void FixVacuum(MapIndices indices) { + if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return; var tile = GetTile(indices); - if (tile?.GridIndex != _grid.Index) return; + if (tile?.GridIndex != mapGrid.Grid.Index) return; var adjacent = GetAdjacentTiles(indices); tile.Air = new GasMixture(GetVolumeForCells(1)){Temperature = Atmospherics.T20C}; _tiles[indices] = tile; @@ -217,16 +218,17 @@ namespace Content.Server.GameObjects.Components.Atmos /// [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; _activeTiles.Add(tile); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RemoveActiveTile(TileAtmosphere tile) + public void RemoveActiveTile(TileAtmosphere? tile) { if (tile == null) return; _activeTiles.Remove(tile); @@ -236,27 +238,29 @@ namespace Content.Server.GameObjects.Components.Atmos /// [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); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RemoveHotspotTile(TileAtmosphere tile) + public void RemoveHotspotTile(TileAtmosphere? tile) { if (tile == null) return; _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); } - public void RemoveSuperconductivityTile(TileAtmosphere tile) + public void RemoveSuperconductivityTile(TileAtmosphere? tile) { if (tile == null) return; _superconductivityTiles.Remove(tile); @@ -264,9 +268,10 @@ namespace Content.Server.GameObjects.Components.Atmos /// [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); } @@ -292,20 +297,22 @@ namespace Content.Server.GameObjects.Components.Atmos } /// - public TileAtmosphere GetTile(GridCoordinates coordinates) + public TileAtmosphere? GetTile(GridCoordinates coordinates) { return GetTile(coordinates.ToMapIndices(_mapManager)); } /// - 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; // We don't have that tile! 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(); return space; } @@ -324,7 +331,9 @@ namespace Content.Server.GameObjects.Components.Atmos public bool IsSpace(MapIndices indices) { // 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 GetAdjacentTiles(MapIndices indices, bool includeAirBlocked = false) @@ -334,7 +343,7 @@ namespace Content.Server.GameObjects.Components.Atmos { var side = indices.Offset(dir); var tile = GetTile(side); - if(tile?.Air != null || includeAirBlocked) + if (tile != null && (tile.Air != null || includeAirBlocked)) sides[dir] = tile; } @@ -349,7 +358,9 @@ namespace Content.Server.GameObjects.Components.Atmos /// 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; } /// @@ -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(out var ac)) return ac; @@ -534,22 +547,24 @@ namespace Content.Server.GameObjects.Components.Atmos public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); - if (serializer.Reading) + if (serializer.Reading && + Owner.TryGetComponent(out IMapGridComponent? mapGrid)) { - var gridId = Owner.GetComponent().Grid.Index; + var gridId = mapGrid.Grid.Index; - if (!serializer.TryReadDataField("uniqueMixes", out List uniqueMixes) || - !serializer.TryReadDataField("tiles", out Dictionary tiles)) + if (!serializer.TryReadDataField("uniqueMixes", out List? uniqueMixes) || + !serializer.TryReadDataField("tiles", out Dictionary? tiles)) return; _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); } - } else if (serializer.Writing) + } + else if (serializer.Writing) { var uniqueMixes = new List(); var uniqueMixHash = new Dictionary(); diff --git a/Content.Server/GameObjects/Components/BarSign/BarSignComponent.cs b/Content.Server/GameObjects/Components/BarSign/BarSignComponent.cs index d6b1ae3233..16827c0dc6 100644 --- a/Content.Server/GameObjects/Components/BarSign/BarSignComponent.cs +++ b/Content.Server/GameObjects/Components/BarSign/BarSignComponent.cs @@ -1,4 +1,5 @@ -using System.Linq; +#nullable enable +using System.Linq; using Content.Server.GameObjects.Components.Power.ApcNetComponents; using Robust.Server.GameObjects; using Robust.Server.Interfaces.GameObjects; @@ -19,18 +20,13 @@ namespace Content.Server.GameObjects.Components.BarSign { public override string Name => "BarSign"; -#pragma warning disable 649 - [Dependency] private readonly IPrototypeManager _prototypeManager; - [Dependency] private readonly IRobustRandom _robustRandom; -#pragma warning restore 649 + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IRobustRandom _robustRandom = default!; - private string _currentSign; - - private PowerReceiverComponent _power; - private SpriteComponent _sprite; + private string? _currentSign; [ViewVariables(VVAccess.ReadWrite)] - public string CurrentSign + public string? CurrentSign { get => _currentSign; set @@ -40,6 +36,8 @@ namespace Content.Server.GameObjects.Components.BarSign } } + private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered; + private void UpdateSignInfo() { if (_currentSign == null) @@ -53,15 +51,18 @@ namespace Content.Server.GameObjects.Components.BarSign return; } - if (!_power.Powered) + if (Owner.TryGetComponent(out SpriteComponent? sprite)) { - _sprite.LayerSetState(0, "empty"); - _sprite.LayerSetShader(0, "shaded"); - } - else - { - _sprite.LayerSetState(0, prototype.Icon); - _sprite.LayerSetShader(0, "unshaded"); + if (!Powered) + { + sprite.LayerSetState(0, "empty"); + sprite.LayerSetShader(0, "shaded"); + } + else + { + sprite.LayerSetState(0, prototype.Icon); + sprite.LayerSetShader(0, "unshaded"); + } } if (!string.IsNullOrEmpty(prototype.Name)) @@ -80,21 +81,25 @@ namespace Content.Server.GameObjects.Components.BarSign { base.Initialize(); - _power = Owner.GetComponent(); - _sprite = Owner.GetComponent(); - - _power.OnPowerStateChanged += PowerOnOnPowerStateChanged; + if (Owner.TryGetComponent(out PowerReceiverComponent? receiver)) + { + receiver.OnPowerStateChanged += PowerOnOnPowerStateChanged; + } UpdateSignInfo(); } public override void OnRemove() { - _power.OnPowerStateChanged -= PowerOnOnPowerStateChanged; + if (Owner.TryGetComponent(out PowerReceiverComponent? receiver)) + { + receiver.OnPowerStateChanged -= PowerOnOnPowerStateChanged; + } + base.OnRemove(); } - private void PowerOnOnPowerStateChanged(object sender, PowerStateEventArgs e) + private void PowerOnOnPowerStateChanged(object? sender, PowerStateEventArgs e) { UpdateSignInfo(); } diff --git a/Content.Server/GameObjects/Components/Body/BodyScannerComponent.cs b/Content.Server/GameObjects/Components/Body/BodyScannerComponent.cs index 2c49665757..be4d6c99c9 100644 --- a/Content.Server/GameObjects/Components/Body/BodyScannerComponent.cs +++ b/Content.Server/GameObjects/Components/Body/BodyScannerComponent.cs @@ -1,10 +1,13 @@ -using System.Collections.Generic; +#nullable enable +using System.Collections.Generic; using Content.Server.Body; using Content.Shared.Body.Scanner; using Content.Shared.Interfaces.GameObjects.Components; using Robust.Server.GameObjects.Components.UserInterface; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; +using Robust.Shared.Log; +using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Body { @@ -12,32 +15,44 @@ namespace Content.Server.GameObjects.Components.Body [ComponentReference(typeof(IActivate))] public class BodyScannerComponent : Component, IActivate { - private BoundUserInterface _userInterface; 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) { - if (!eventArgs.User.TryGetComponent(out IActorComponent actor) || + if (!eventArgs.User.TryGetComponent(out IActorComponent? actor) || actor.playerSession.AttachedEntity == null) { return; } - if (actor.playerSession.AttachedEntity.TryGetComponent(out BodyManagerComponent attempt)) + if (actor.playerSession.AttachedEntity.TryGetComponent(out BodyManagerComponent? attempt)) { 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() { base.Initialize(); - _userInterface = Owner.GetComponent() - .GetBoundUserInterface(BodyScannerUiKey.Key); - _userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; + + if (UserInterface == null) + { + Logger.Warning($"Entity {Owner} at {Owner.Transform.MapPosition} doesn't have a {nameof(ServerUserInterfaceComponent)}"); + } + else + { + UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; + } } private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg) { } diff --git a/Content.Server/GameObjects/Components/Body/Digestive/StomachComponent.cs b/Content.Server/GameObjects/Components/Body/Digestive/StomachComponent.cs index fa6b76caea..15c6d01e82 100644 --- a/Content.Server/GameObjects/Components/Body/Digestive/StomachComponent.cs +++ b/Content.Server/GameObjects/Components/Body/Digestive/StomachComponent.cs @@ -1,12 +1,11 @@ -using System.Collections.Generic; +#nullable enable +using System.Collections.Generic; using System.Linq; using Content.Server.GameObjects.Components.Body.Circulatory; using Content.Server.GameObjects.Components.Chemistry; using Content.Shared.Chemistry; using Content.Shared.GameObjects.Components.Nutrition; using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Localization; using Robust.Shared.Log; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -20,25 +19,21 @@ namespace Content.Server.GameObjects.Components.Body.Digestive [RegisterComponent] public class StomachComponent : SharedStomachComponent { -#pragma warning disable 649 - [Dependency] private readonly ILocalizationManager _localizationManager; -#pragma warning restore 649 - /// /// Max volume of internal solution storage /// public ReagentUnit MaxVolume { - get => _stomachContents.MaxVolume; - set => _stomachContents.MaxVolume = value; + get => Owner.TryGetComponent(out SolutionComponent? solution) ? solution.MaxVolume : ReagentUnit.Zero; + set + { + if (Owner.TryGetComponent(out SolutionComponent? solution)) + { + solution.MaxVolume = value; + } + } } - /// - /// Internal solution storage - /// - [ViewVariables] - private SolutionComponent _stomachContents; - /// /// Initial internal solution storage volume /// @@ -68,20 +63,29 @@ namespace Content.Server.GameObjects.Components.Body.Digestive { base.Startup(); - _stomachContents = Owner.GetComponent(); - _stomachContents.MaxVolume = _initialMaxVolume; + if (!Owner.EnsureComponent(out SolutionComponent solution)) + { + Logger.Warning($"Entity {Owner} at {Owner.Transform.MapPosition} didn't have a {nameof(SolutionComponent)}"); + } + + solution.MaxVolume = _initialMaxVolume; } public bool TryTransferSolution(Solution solution) { + if (!Owner.TryGetComponent(out SolutionComponent? solutionComponent)) + { + return false; + } + // 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; } // 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 foreach (var reagent in solution.Contents) { @@ -99,7 +103,8 @@ namespace Content.Server.GameObjects.Components.Body.Digestive /// The time since the last update in seconds. public void Update(float frameTime) { - if (!Owner.TryGetComponent(out BloodstreamComponent bloodstream)) + if (!Owner.TryGetComponent(out SolutionComponent? solutionComponent) || + !Owner.TryGetComponent(out BloodstreamComponent? bloodstream)) { return; } @@ -114,7 +119,7 @@ namespace Content.Server.GameObjects.Components.Body.Digestive delta.Increment(frameTime); if (delta.Lifetime > _digestionDelay) { - _stomachContents.TryRemoveReagent(delta.ReagentId, delta.Quantity); + solutionComponent.TryRemoveReagent(delta.ReagentId, delta.Quantity); transferSolution.AddReagent(delta.ReagentId, delta.Quantity); _reagentDeltas.Remove(delta); } diff --git a/Content.Server/GameObjects/Components/Body/DroppedBodyPartComponent.cs b/Content.Server/GameObjects/Components/Body/DroppedBodyPartComponent.cs index 431f60e026..cce6566879 100644 --- a/Content.Server/GameObjects/Components/Body/DroppedBodyPartComponent.cs +++ b/Content.Server/GameObjects/Components/Body/DroppedBodyPartComponent.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +#nullable enable +using System.Collections.Generic; using System.Linq; using Content.Shared.Interfaces; using Content.Shared.Interfaces.GameObjects.Components; @@ -6,6 +7,7 @@ using Content.Server.Body; using Content.Shared.Body.Surgery; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.UserInterface; +using Robust.Server.Interfaces.GameObjects; using Robust.Server.Interfaces.Player; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; @@ -21,20 +23,23 @@ namespace Content.Server.GameObjects.Components.Body [RegisterComponent] public class DroppedBodyPartComponent : Component, IAfterInteract, IBodyPartContainer { -#pragma warning disable 649 - [Dependency] private readonly ISharedNotifyManager _sharedNotifyManager; -#pragma warning restore 649 + [Dependency] private readonly ISharedNotifyManager _sharedNotifyManager = default!; private readonly Dictionary _optionsCache = new Dictionary(); - private BodyManagerComponent _bodyManagerComponentCache; + private BodyManagerComponent? _bodyManagerComponentCache; private int _idHash; - private IEntity _performerCache; - - private BoundUserInterface _userInterface; + private IEntity? _performerCache; 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) { @@ -48,7 +53,7 @@ namespace Content.Server.GameObjects.Components.Body _performerCache = null; _bodyManagerComponentCache = null; - if (eventArgs.Target.TryGetComponent(out BodyManagerComponent bodyManager)) + if (eventArgs.Target.TryGetComponent(out BodyManagerComponent? bodyManager)) { SendBodySlotListToUser(eventArgs, bodyManager); } @@ -58,9 +63,10 @@ namespace Content.Server.GameObjects.Components.Body { base.Initialize(); - _userInterface = Owner.GetComponent() - .GetBoundUserInterface(GenericSurgeryUiKey.Key); - _userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; + } } public void TransferBodyPartData(BodyPart data) @@ -68,7 +74,7 @@ namespace Content.Server.GameObjects.Components.Body ContainedBodyPart = data; Owner.Name = Loc.GetString(ContainedBodyPart.Name); - if (Owner.TryGetComponent(out SpriteComponent component)) + if (Owner.TryGetComponent(out SpriteComponent? component)) { component.LayerSetRSI(0, data.RSIPath); component.LayerSetState(0, data.RSIState); @@ -91,7 +97,7 @@ namespace Content.Server.GameObjects.Components.Body foreach (var slot in unoccupiedSlots) { if (!bodyManager.TryGetSlotType(slot, out var typeResult) || - typeResult != ContainedBodyPart.PartType || + typeResult != ContainedBodyPart?.PartType || !bodyManager.TryGetBodyPartConnections(slot, out var parts)) { continue; @@ -129,7 +135,18 @@ namespace Content.Server.GameObjects.Components.Body /// private void HandleReceiveBodyPartSlot(int key) { - CloseSurgeryUI(_performerCache.GetComponent().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 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)); } - 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( _bodyManagerComponentCache.Owner, _performerCache, - !_bodyManagerComponentCache.InstallDroppedBodyPart(this, target) - ? Loc.GetString("You can't attach it!") - : Loc.GetString("You attach {0:theName}.", ContainedBodyPart)); + message); } private void OpenSurgeryUI(IPlayerSession session) { - _userInterface.Open(session); + UserInterface?.Open(session); } private void UpdateSurgeryUIBodyPartSlotRequest(IPlayerSession session, Dictionary options) { - _userInterface.SendMessage(new RequestBodyPartSlotSurgeryUIMessage(options), session); + UserInterface?.SendMessage(new RequestBodyPartSlotSurgeryUIMessage(options), session); } private void CloseSurgeryUI(IPlayerSession session) { - _userInterface.Close(session); + UserInterface?.Close(session); } private void CloseAllSurgeryUIs() { - _userInterface.CloseAll(); + UserInterface?.CloseAll(); } private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage message) diff --git a/Content.Server/GameObjects/Components/Body/DroppedMechanismComponent.cs b/Content.Server/GameObjects/Components/Body/DroppedMechanismComponent.cs index 58cab75d74..92af831132 100644 --- a/Content.Server/GameObjects/Components/Body/DroppedMechanismComponent.cs +++ b/Content.Server/GameObjects/Components/Body/DroppedMechanismComponent.cs @@ -1,4 +1,4 @@ -using System; +#nullable enable using System.Collections.Generic; using Content.Server.Body; using Content.Server.Body.Mechanisms; @@ -8,14 +8,15 @@ using Content.Shared.Interfaces; using Content.Shared.Interfaces.GameObjects.Components; using Robust.Server.GameObjects; using Robust.Server.GameObjects.Components.UserInterface; +using Robust.Server.Interfaces.GameObjects; using Robust.Server.Interfaces.Player; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Localization; -using Robust.Shared.Log; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; +using Robust.Shared.Utility; using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Body @@ -26,24 +27,27 @@ namespace Content.Server.GameObjects.Components.Body [RegisterComponent] public class DroppedMechanismComponent : Component, IAfterInteract { -#pragma warning disable 649 - [Dependency] private readonly ISharedNotifyManager _sharedNotifyManager; - [Dependency] private IPrototypeManager _prototypeManager; -#pragma warning restore 649 + [Dependency] private readonly ISharedNotifyManager _sharedNotifyManager = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; public sealed override string Name => "DroppedMechanism"; private readonly Dictionary _optionsCache = new Dictionary(); - private BodyManagerComponent _bodyManagerComponentCache; + private BodyManagerComponent? _bodyManagerComponentCache; 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) { @@ -63,12 +67,7 @@ namespace Content.Server.GameObjects.Components.Body } else if (eventArgs.Target.TryGetComponent(out var droppedBodyPart)) { - if (droppedBodyPart.ContainedBodyPart == null) - { - 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!"); - } + DebugTools.AssertNotNull(droppedBodyPart.ContainedBodyPart); if (!droppedBodyPart.ContainedBodyPart.TryInstallDroppedMechanism(this)) { @@ -82,9 +81,10 @@ namespace Content.Server.GameObjects.Components.Body { base.Initialize(); - _userInterface = Owner.GetComponent() - .GetBoundUserInterface(GenericSurgeryUiKey.Key); - _userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; + } } public void InitializeDroppedMechanism(Mechanism data) @@ -92,7 +92,7 @@ namespace Content.Server.GameObjects.Components.Body ContainedMechanism = data; Owner.Name = Loc.GetString(ContainedMechanism.Name); - if (Owner.TryGetComponent(out SpriteComponent component)) + if (Owner.TryGetComponent(out SpriteComponent? component)) { component.LayerSetRSI(0, data.RSIPath); component.LayerSetState(0, data.RSIState); @@ -111,7 +111,7 @@ namespace Content.Server.GameObjects.Components.Body if (serializer.Reading && debugLoadMechanismData != "") { - _prototypeManager.TryIndex(debugLoadMechanismData, out MechanismPrototype data); + _prototypeManager.TryIndex(debugLoadMechanismData!, out MechanismPrototype data); var mechanism = new Mechanism(data); mechanism.EnsureInitialize(); @@ -155,7 +155,18 @@ namespace Content.Server.GameObjects.Components.Body /// private void HandleReceiveBodyPart(int key) { - CloseSurgeryUI(_performerCache.GetComponent().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 if (!_optionsCache.TryGetValue(key, out var targetObject)) @@ -165,36 +176,37 @@ namespace Content.Server.GameObjects.Components.Body 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( _bodyManagerComponentCache.Owner, _performerCache, - !target.TryInstallDroppedMechanism(this) - ? Loc.GetString("You can't fit it in!") - : Loc.GetString("You jam the {1} inside {0:them}.", _performerCache, ContainedMechanism.Name)); + message); // TODO: {1:theName} } private void OpenSurgeryUI(IPlayerSession session) { - _userInterface.Open(session); + UserInterface?.Open(session); } private void UpdateSurgeryUIBodyPartRequest(IPlayerSession session, Dictionary options) { - _userInterface.SendMessage(new RequestBodyPartSurgeryUIMessage(options), session); + UserInterface?.SendMessage(new RequestBodyPartSurgeryUIMessage(options), session); } private void CloseSurgeryUI(IPlayerSession session) { - _userInterface.Close(session); + UserInterface?.Close(session); } private void CloseAllSurgeryUIs() { - _userInterface.CloseAll(); + UserInterface?.CloseAll(); } private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage message) diff --git a/Content.Server/GameObjects/Components/Body/SurgeryToolComponent.cs b/Content.Server/GameObjects/Components/Body/SurgeryToolComponent.cs index 7f4ece43a0..9f55f87a49 100644 --- a/Content.Server/GameObjects/Components/Body/SurgeryToolComponent.cs +++ b/Content.Server/GameObjects/Components/Body/SurgeryToolComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Collections.Generic; using Content.Server.Body; using Content.Server.Body.Mechanisms; @@ -18,6 +19,8 @@ using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Log; using Robust.Shared.Serialization; +using Robust.Shared.Utility; +using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Body { @@ -30,9 +33,7 @@ namespace Content.Server.GameObjects.Components.Body [RegisterComponent] public class SurgeryToolComponent : Component, ISurgeon, IAfterInteract { -#pragma warning disable 649 - [Dependency] private readonly ISharedNotifyManager _sharedNotifyManager; -#pragma warning restore 649 + [Dependency] private readonly ISharedNotifyManager _sharedNotifyManager = default!; public override string Name => "SurgeryTool"; public override uint? NetID => ContentNetIDs.SURGERY; @@ -41,17 +42,22 @@ namespace Content.Server.GameObjects.Components.Body private float _baseOperateTime; - private BodyManagerComponent _bodyManagerComponentCache; + private BodyManagerComponent? _bodyManagerComponentCache; - private ISurgeon.MechanismRequestCallback _callbackCache; + private ISurgeon.MechanismRequestCallback? _callbackCache; private int _idHash; - private IEntity _performerCache; + private IEntity? _performerCache; 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) { @@ -60,7 +66,7 @@ namespace Content.Server.GameObjects.Components.Body return; } - if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) + if (!eventArgs.User.TryGetComponent(out IActorComponent? actor)) { return; } @@ -73,7 +79,7 @@ namespace Content.Server.GameObjects.Components.Body _callbackCache = null; // 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) var toSend = new Dictionary(); @@ -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 _performerCache = eventArgs.User; - if (droppedBodyPart.ContainedBodyPart == null) - { - // 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!"); - } + DebugTools.AssertNotNull(droppedBodyPart.ContainedBodyPart); // If surgery can be performed... if (!droppedBodyPart.ContainedBodyPart.SurgeryCheck(_surgeryType)) @@ -144,7 +144,7 @@ namespace Content.Server.GameObjects.Components.Body toSend.Add(mechanism.Name, _idHash++); } - if (_optionsCache.Count > 0) + if (_optionsCache.Count > 0 && _performerCache != null) { OpenSurgeryUI(_performerCache.GetComponent().playerSession); UpdateSurgeryUIMechanismRequest(_performerCache.GetComponent().playerSession, @@ -162,34 +162,35 @@ namespace Content.Server.GameObjects.Components.Body { base.Initialize(); - _userInterface = Owner.GetComponent() - .GetBoundUserInterface(GenericSurgeryUiKey.Key); - _userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; + } } private void OpenSurgeryUI(IPlayerSession session) { - _userInterface.Open(session); + UserInterface?.Open(session); } private void UpdateSurgeryUIBodyPartRequest(IPlayerSession session, Dictionary options) { - _userInterface.SendMessage(new RequestBodyPartSurgeryUIMessage(options), session); + UserInterface?.SendMessage(new RequestBodyPartSurgeryUIMessage(options), session); } private void UpdateSurgeryUIMechanismRequest(IPlayerSession session, Dictionary options) { - _userInterface.SendMessage(new RequestMechanismSurgeryUIMessage(options), session); + UserInterface?.SendMessage(new RequestMechanismSurgeryUIMessage(options), session); } private void CloseSurgeryUI(IPlayerSession session) { - _userInterface.Close(session); + UserInterface?.Close(session); } private void CloseAllSurgeryUIs() { - _userInterface.CloseAll(); + UserInterface?.CloseAll(); } private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage message) @@ -211,14 +212,22 @@ namespace Content.Server.GameObjects.Components.Body /// private void HandleReceiveBodyPart(int key) { - CloseSurgeryUI(_performerCache.GetComponent().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)) + if (_performerCache == null || + !_performerCache.TryGetComponent(out IActorComponent? actor)) { - 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)) { @@ -233,19 +242,27 @@ namespace Content.Server.GameObjects.Components.Body 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 - if (!_optionsCache.TryGetValue(key, out var targetObject)) + if (!_optionsCache.TryGetValue(key, out var targetObject) || + _performerCache == null || + !_performerCache.TryGetComponent(out IActorComponent? actor)) { SendNoUsefulWayToUseAnymorePopup(); + return; } var target = targetObject as Mechanism; - CloseSurgeryUI(_performerCache.GetComponent().playerSession); - _callbackCache(target, _bodyManagerComponentCache, this, _performerCache); + CloseSurgeryUI(actor.playerSession); + _callbackCache?.Invoke(target, _bodyManagerComponentCache, this, _performerCache); } private void SendNoUsefulWayToUsePopup() { + if (_bodyManagerComponentCache == null) + { + return; + } + _sharedNotifyManager.PopupMessage( _bodyManagerComponentCache.Owner, _performerCache, @@ -254,6 +271,11 @@ namespace Content.Server.GameObjects.Components.Body private void SendNoUsefulWayToUseAnymorePopup() { + if (_bodyManagerComponentCache == null) + { + return; + } + _sharedNotifyManager.PopupMessage( _bodyManagerComponentCache.Owner, _performerCache, diff --git a/Content.Server/GameObjects/Components/Buckle/BuckleComponent.cs b/Content.Server/GameObjects/Components/Buckle/BuckleComponent.cs index fcb1144b47..0b15560869 100644 --- a/Content.Server/GameObjects/Components/Buckle/BuckleComponent.cs +++ b/Content.Server/GameObjects/Components/Buckle/BuckleComponent.cs @@ -34,13 +34,11 @@ namespace Content.Server.GameObjects.Components.Buckle [RegisterComponent] public class BuckleComponent : SharedBuckleComponent, IInteractHand, IDragDrop { -#pragma warning disable 649 [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IEntitySystemManager _entitySystem = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IServerNotifyManager _notifyManager = default!; [Dependency] private readonly IMapManager _mapManager = default!; -#pragma warning restore 649 private int _size; diff --git a/Content.Server/GameObjects/Components/Cargo/CargoConsoleComponent.cs b/Content.Server/GameObjects/Components/Cargo/CargoConsoleComponent.cs index ca6445e5e6..658fcec180 100644 --- a/Content.Server/GameObjects/Components/Cargo/CargoConsoleComponent.cs +++ b/Content.Server/GameObjects/Components/Cargo/CargoConsoleComponent.cs @@ -10,6 +10,7 @@ using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.IoC; +using Robust.Shared.Log; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -19,21 +20,11 @@ namespace Content.Server.GameObjects.Components.Cargo [ComponentReference(typeof(IActivate))] public class CargoConsoleComponent : SharedCargoConsoleComponent, IActivate { -#pragma warning disable 649 [Dependency] private readonly ICargoOrderDataManager _cargoOrderDataManager = default!; -#pragma warning restore 649 [ViewVariables] 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; [ViewVariables] @@ -65,22 +56,49 @@ namespace Content.Server.GameObjects.Components.Cargo private bool _requestOnly = false; - private PowerReceiverComponent _powerReceiver = default!; - private bool Powered => _powerReceiver.Powered; + private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered; 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() { base.Initialize(); - Market = Owner.GetComponent(); - Orders = Owner.GetComponent(); - _userInterface = Owner.GetComponent().GetBoundUserInterface(CargoConsoleUiKey.Key); - _userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; - _powerReceiver = Owner.GetComponent(); + + if (!Owner.EnsureComponent(out GalacticMarketComponent _)) + { + Logger.Warning($"Entity {Owner} at {Owner.Transform.MapPosition} had no {nameof(GalacticMarketComponent)}"); + } + + 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(); BankAccount = _cargoConsoleSystem.StationAccount; } + public override void OnRemove() + { + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; + } + + base.OnRemove(); + } + /// /// Reads data from YAML /// @@ -93,8 +111,13 @@ namespace Content.Server.GameObjects.Components.Cargo private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg) { + if (!Owner.TryGetComponent(out CargoOrderDatabaseComponent? orders)) + { + return; + } + var message = serverMsg.Message; - if (!Orders.ConnectedToDatabase) + if (!orders.ConnectedToDatabase) return; if (!Powered) return; @@ -107,39 +130,39 @@ namespace Content.Server.GameObjects.Components.Cargo 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; } case CargoConsoleRemoveOrderMessage msg: { - _cargoOrderDataManager.RemoveOrder(Orders.Database.Id, msg.OrderNumber); + _cargoOrderDataManager.RemoveOrder(orders.Database.Id, msg.OrderNumber); break; } case CargoConsoleApproveOrderMessage msg: { if (_requestOnly || - !Orders.Database.TryGetOrder(msg.OrderNumber, out var order) || + !orders.Database.TryGetOrder(msg.OrderNumber, out var order) || _bankAccount == null) { break; } _prototypeManager.TryIndex(order.ProductId, out CargoProductPrototype product); - if (product == null) + if (product == null!) break; - var capacity = _cargoOrderDataManager.GetCapacity(Orders.Database.Id); + var capacity = _cargoOrderDataManager.GetCapacity(orders.Database.Id); if (capacity.CurrentCapacity == capacity.MaxCapacity) break; if (!_cargoConsoleSystem.ChangeBalance(_bankAccount.Id, (-product.PointCost) * order.Amount)) break; - _cargoOrderDataManager.ApproveOrder(Orders.Database.Id, msg.OrderNumber); + _cargoOrderDataManager.ApproveOrder(orders.Database.Id, msg.OrderNumber); UpdateUIState(); break; } case CargoConsoleShuttleMessage _: { - var approvedOrders = _cargoOrderDataManager.RemoveAndGetApprovedFrom(Orders.Database); - Orders.Database.ClearOrderCapacity(); + var approvedOrders = _cargoOrderDataManager.RemoveAndGetApprovedFrom(orders.Database); + orders.Database.ClearOrderCapacity(); // TODO replace with shuttle code // TEMPORARY loop for spawning stuff on top of console @@ -166,12 +189,12 @@ namespace Content.Server.GameObjects.Components.Cargo if (!Powered) return; - _userInterface.Open(actor.playerSession); + UserInterface?.Open(actor.playerSession); } private void UpdateUIState() { - if (_bankAccount == null) + if (_bankAccount == null || !Owner.IsValid()) { return; } @@ -180,7 +203,7 @@ namespace Content.Server.GameObjects.Components.Cargo var name = _bankAccount.Name; var balance = _bankAccount.Balance; var capacity = _cargoOrderDataManager.GetCapacity(id); - _userInterface.SetState(new CargoConsoleInterfaceState(_requestOnly, id, name, balance, capacity)); + UserInterface?.SetState(new CargoConsoleInterfaceState(_requestOnly, id, name, balance, capacity)); } } } diff --git a/Content.Server/GameObjects/Components/Chemistry/ChemMasterComponent.cs b/Content.Server/GameObjects/Components/Chemistry/ChemMasterComponent.cs index 156b9efefb..84cc2ca642 100644 --- a/Content.Server/GameObjects/Components/Chemistry/ChemMasterComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/ChemMasterComponent.cs @@ -1,4 +1,6 @@ -using System; +#nullable enable +using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Content.Server.GameObjects.Components.GUI; @@ -40,24 +42,26 @@ namespace Content.Server.GameObjects.Components.Chemistry [ComponentReference(typeof(IInteractUsing))] public class ChemMasterComponent : SharedChemMasterComponent, IActivate, IInteractUsing, ISolutionChange { -#pragma warning disable 649 - [Dependency] private readonly IServerNotifyManager _notifyManager; - [Dependency] private readonly ILocalizationManager _localizationManager; -#pragma warning restore 649 + [Dependency] private readonly IServerNotifyManager _notifyManager = default!; + [Dependency] private readonly ILocalizationManager _localizationManager = default!; - [ViewVariables] private BoundUserInterface _userInterface; - [ViewVariables] private ContainerSlot _beakerContainer; - [ViewVariables] private string _packPrototypeId; + [ViewVariables] private ContainerSlot _beakerContainer = default!; + [ViewVariables] private string _packPrototypeId = ""; [ViewVariables] private bool HasBeaker => _beakerContainer.ContainedEntity != null; - [ViewVariables] private bool BufferModeTransfer = true; + [ViewVariables] private bool _bufferModeTransfer = true; - private PowerReceiverComponent _powerReceiver; - private bool Powered => _powerReceiver.Powered; + private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered; private readonly SolutionComponent BufferSolution = new SolutionComponent(); + [ViewVariables] + private BoundUserInterface? UserInterface => + Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) && + ui.TryGetBoundUserInterface(ChemMasterUiKey.Key, out var boundUi) + ? boundUi + : null; /// /// 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() { base.Initialize(); - _userInterface = Owner.GetComponent() - .GetBoundUserInterface(ChemMasterUiKey.Key); - _userInterface.OnReceiveMessage += OnUiReceiveMessage; + + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += OnUiReceiveMessage; + } _beakerContainer = ContainerManagerComponent.Ensure($"{Name}-reagentContainerContainer", Owner); - _powerReceiver = Owner.GetComponent(); - _powerReceiver.OnPowerStateChanged += OnPowerChanged; + + if (Owner.TryGetComponent(out PowerReceiverComponent? receiver)) + { + receiver.OnPowerStateChanged += OnPowerChanged; + } //BufferSolution = Owner.BufferSolution BufferSolution.Solution = new Solution(); @@ -93,7 +102,7 @@ namespace Content.Server.GameObjects.Components.Chemistry UpdateUserInterface(); } - private void OnPowerChanged(object sender, PowerStateEventArgs e) + private void OnPowerChanged(object? sender, PowerStateEventArgs e) { UpdateUserInterface(); } @@ -105,6 +114,11 @@ namespace Content.Server.GameObjects.Components.Chemistry /// A user interface message from the client. private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj) { + if (obj.Session.AttachedEntity == null) + { + return; + } + var msg = (UiActionMessage) obj.Message; var needsPower = msg.action switch { @@ -124,11 +138,11 @@ namespace Content.Server.GameObjects.Components.Chemistry TransferReagent(msg.id, msg.amount, msg.isBuffer); break; case UiAction.Transfer: - BufferModeTransfer = true; + _bufferModeTransfer = true; UpdateUserInterface(); break; case UiAction.Discard: - BufferModeTransfer = false; + _bufferModeTransfer = false; UpdateUserInterface(); break; case UiAction.CreatePills: @@ -147,7 +161,7 @@ namespace Content.Server.GameObjects.Components.Chemistry /// /// The player entity. /// Returns true if the entity can use the chem master, and false if it cannot. - 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 if (playerEntity == null) @@ -172,18 +186,18 @@ namespace Content.Server.GameObjects.Components.Chemistry if (beaker == null) { 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(), BufferSolution.ReagentList.ToList(), _bufferModeTransfer, BufferSolution.CurrentVolume, BufferSolution.MaxVolume); } var solution = beaker.GetComponent(); 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() { var state = GetUserInterfaceState(); - _userInterface.SetState(state); + UserInterface?.SetState(state); } /// @@ -207,7 +221,7 @@ namespace Content.Server.GameObjects.Components.Chemistry private void TransferReagent(string id, ReagentUnit amount, bool isBuffer) { - if (!HasBeaker && BufferModeTransfer) return; + if (!HasBeaker && _bufferModeTransfer) return; var beaker = _beakerContainer.ContainedEntity; var beakerSolution = beaker.GetComponent(); if (isBuffer) @@ -227,7 +241,7 @@ namespace Content.Server.GameObjects.Components.Chemistry } BufferSolution.Solution.RemoveReagent(id, actualAmount); - if (BufferModeTransfer) + if (_bufferModeTransfer) { beakerSolution.Solution.AddReagent(id, actualAmount); } @@ -351,12 +365,12 @@ namespace Content.Server.GameObjects.Components.Chemistry /// Data relevant to the event such as the actor which triggered it. void IActivate.Activate(ActivateEventArgs args) { - if (!args.User.TryGetComponent(out IActorComponent actor)) + if (!args.User.TryGetComponent(out IActorComponent? actor)) { return; } - if (!args.User.TryGetComponent(out IHandsComponent hands)) + if (!args.User.TryGetComponent(out IHandsComponent? hands)) { _notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User, _localizationManager.GetString("You have no hands.")); @@ -366,7 +380,7 @@ namespace Content.Server.GameObjects.Components.Chemistry var activeHandEntity = hands.GetActiveHand?.Owner; if (activeHandEntity == null) { - _userInterface.Open(actor.playerSession); + UserInterface?.Open(actor.playerSession); } } @@ -379,13 +393,20 @@ namespace Content.Server.GameObjects.Components.Chemistry /// async Task 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, _localizationManager.GetString("You have no hands.")); 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; if (activeHandEntity.TryGetComponent(out var solution)) { diff --git a/Content.Server/GameObjects/Components/Chemistry/InjectorComponent.cs b/Content.Server/GameObjects/Components/Chemistry/InjectorComponent.cs index 03ac3855e7..a3a9959ca1 100644 --- a/Content.Server/GameObjects/Components/Chemistry/InjectorComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/InjectorComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using Content.Server.GameObjects.Components.Body.Circulatory; using Content.Server.Interfaces; using Content.Server.Utility; @@ -22,9 +23,7 @@ namespace Content.Server.GameObjects.Components.Chemistry [RegisterComponent] public class InjectorComponent : SharedInjectorComponent, IAfterInteract, IUse { -#pragma warning disable 649 - [Dependency] private readonly IServerNotifyManager _notifyManager; -#pragma warning restore 649 + [Dependency] private readonly IServerNotifyManager _notifyManager = default!; /// /// 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 /// [ViewVariables(VVAccess.ReadWrite)] private InjectorToggleMode _toggleState; - /// - /// Internal solution container - /// - [ViewVariables] - private SolutionComponent _internalContents; public override void ExposeData(ObjectSerializer serializer) { @@ -69,9 +63,15 @@ namespace Content.Server.GameObjects.Components.Chemistry protected override void Startup() { base.Startup(); - _internalContents = Owner.GetComponent(); - _internalContents.Capabilities |= SolutionCaps.Injector; - //Set _toggleState based on prototype + + Owner.EnsureComponent(); + + if (Owner.TryGetComponent(out SolutionComponent? solution)) + { + solution.Capabilities |= SolutionCaps.Injector; + } + + // Set _toggleState based on prototype _toggleState = _injectOnly ? InjectorToggleMode.Inject : InjectorToggleMode.Draw; } @@ -114,7 +114,7 @@ namespace Content.Server.GameObjects.Components.Chemistry if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return; //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; } @@ -134,7 +134,7 @@ namespace Content.Server.GameObjects.Components.Chemistry } else //Handle injecting into bloodstream { - if (targetEntity.TryGetComponent(out BloodstreamComponent bloodstream) && + if (targetEntity.TryGetComponent(out BloodstreamComponent? bloodstream) && _toggleState == InjectorToggleMode.Inject) { TryInjectIntoBloodstream(bloodstream, eventArgs.User); @@ -155,7 +155,8 @@ namespace Content.Server.GameObjects.Components.Chemistry private void TryInjectIntoBloodstream(BloodstreamComponent targetBloodstream, IEntity user) { - if (_internalContents.CurrentVolume == 0) + if (!Owner.TryGetComponent(out SolutionComponent? solution) || + solution.CurrentVolume == 0) { return; } @@ -170,7 +171,7 @@ namespace Content.Server.GameObjects.Components.Chemistry } //Move units from attackSolution to targetSolution - var removedSolution = _internalContents.SplitSolution(realTransferAmount); + var removedSolution = solution.SplitSolution(realTransferAmount); if (!targetBloodstream.TryTransferSolution(removedSolution)) { return; @@ -183,7 +184,8 @@ namespace Content.Server.GameObjects.Components.Chemistry private void TryInject(SolutionComponent targetSolution, IEntity user) { - if (_internalContents.CurrentVolume == 0) + if (!Owner.TryGetComponent(out SolutionComponent? solution) || + solution.CurrentVolume == 0) { return; } @@ -198,7 +200,7 @@ namespace Content.Server.GameObjects.Components.Chemistry } //Move units from attackSolution to targetSolution - var removedSolution = _internalContents.SplitSolution(realTransferAmount); + var removedSolution = solution.SplitSolution(realTransferAmount); if (!targetSolution.TryAddSolution(removedSolution)) { return; @@ -211,7 +213,8 @@ namespace Content.Server.GameObjects.Components.Chemistry private void TryDraw(SolutionComponent targetSolution, IEntity user) { - if (_internalContents.EmptyVolume == 0) + if (!Owner.TryGetComponent(out SolutionComponent? solution) || + solution.EmptyVolume == 0) { return; } @@ -227,7 +230,7 @@ namespace Content.Server.GameObjects.Components.Chemistry //Move units from attackSolution to targetSolution var removedSolution = targetSolution.SplitSolution(realTransferAmount); - if (!_internalContents.TryAddSolution(removedSolution)) + if (!solution.TryAddSolution(removedSolution)) { return; } @@ -239,7 +242,12 @@ namespace Content.Server.GameObjects.Components.Chemistry 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); } } } diff --git a/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs b/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs index d32ae288ad..ae227b58b5 100644 --- a/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Linq; using System.Threading.Tasks; using Content.Server.GameObjects.Components.GUI; @@ -38,14 +39,11 @@ namespace Content.Server.GameObjects.Components.Chemistry [ComponentReference(typeof(IInteractUsing))] public class ReagentDispenserComponent : SharedReagentDispenserComponent, IActivate, IInteractUsing, ISolutionChange { -#pragma warning disable 649 - [Dependency] private readonly IServerNotifyManager _notifyManager; - [Dependency] private readonly ILocalizationManager _localizationManager; -#pragma warning restore 649 + [Dependency] private readonly IServerNotifyManager _notifyManager = default!; + [Dependency] private readonly ILocalizationManager _localizationManager = default!; - [ViewVariables] private BoundUserInterface _userInterface; - [ViewVariables] private ContainerSlot _beakerContainer; - [ViewVariables] private string _packPrototypeId; + [ViewVariables] private ContainerSlot _beakerContainer = default!; + [ViewVariables] private string _packPrototypeId = ""; [ViewVariables] private bool HasBeaker => _beakerContainer.ContainedEntity != null; [ViewVariables] private ReagentUnit _dispenseAmount = ReagentUnit.New(10); @@ -53,9 +51,14 @@ namespace Content.Server.GameObjects.Components.Chemistry [ViewVariables] private SolutionComponent Solution => _beakerContainer.ContainedEntity.GetComponent(); - private PowerReceiverComponent _powerReceiver; - 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(ReagentDispenserUiKey.Key, out var boundUi) + ? boundUi + : null; /// /// 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() { base.Initialize(); - _userInterface = Owner.GetComponent() - .GetBoundUserInterface(ReagentDispenserUiKey.Key); - _userInterface.OnReceiveMessage += OnUiReceiveMessage; + + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += OnUiReceiveMessage; + } _beakerContainer = ContainerManagerComponent.Ensure($"{Name}-reagentContainerContainer", Owner); - _powerReceiver = Owner.GetComponent(); - _powerReceiver.OnPowerStateChanged += OnPowerChanged; + + if (Owner.TryGetComponent(out PowerReceiverComponent? receiver)) + { + receiver.OnPowerStateChanged += OnPowerChanged; + } InitializeFromPrototype(); 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(); } @@ -120,6 +128,11 @@ namespace Content.Server.GameObjects.Components.Chemistry /// A user interface message from the client. private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj) { + if (obj.Session.AttachedEntity == null) + { + return; + } + var msg = (UiButtonPressedMessage) obj.Message; var needsPower = msg.Button switch { @@ -175,7 +188,7 @@ namespace Content.Server.GameObjects.Components.Chemistry /// /// The player entity. /// Returns true if the entity can use the dispenser, and false if it cannot. - 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 if (playerEntity == null) @@ -211,7 +224,7 @@ namespace Content.Server.GameObjects.Components.Chemistry private void UpdateUserInterface() { var state = GetUserInterfaceState(); - _userInterface.SetState(state); + UserInterface?.SetState(state); } /// @@ -265,12 +278,12 @@ namespace Content.Server.GameObjects.Components.Chemistry /// Data relevant to the event such as the actor which triggered it. void IActivate.Activate(ActivateEventArgs args) { - if (!args.User.TryGetComponent(out IActorComponent actor)) + if (!args.User.TryGetComponent(out IActorComponent? actor)) { return; } - if (!args.User.TryGetComponent(out IHandsComponent hands)) + if (!args.User.TryGetComponent(out IHandsComponent? hands)) { _notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User, _localizationManager.GetString("You have no hands.")); @@ -280,7 +293,7 @@ namespace Content.Server.GameObjects.Components.Chemistry var activeHandEntity = hands.GetActiveHand?.Owner; if (activeHandEntity == null) { - _userInterface.Open(actor.playerSession); + UserInterface?.Open(actor.playerSession); } } @@ -293,13 +306,20 @@ namespace Content.Server.GameObjects.Components.Chemistry /// async Task 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, _localizationManager.GetString("You have no hands.")); 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; if (activeHandEntity.TryGetComponent(out var solution)) { diff --git a/Content.Server/GameObjects/Components/Chemistry/TransformableContainerComponent.cs b/Content.Server/GameObjects/Components/Chemistry/TransformableContainerComponent.cs index 94d18c734e..571e78f64f 100644 --- a/Content.Server/GameObjects/Components/Chemistry/TransformableContainerComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/TransformableContainerComponent.cs @@ -1,4 +1,5 @@ -using Content.Server.GameObjects.EntitySystems; +#nullable enable +using Content.Server.GameObjects.EntitySystems; using Content.Shared.Chemistry; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; @@ -11,28 +12,27 @@ namespace Content.Server.GameObjects.Components.Chemistry [RegisterComponent] public class TransformableContainerComponent : Component, ISolutionChange { -#pragma warning disable 649 - [Dependency] private readonly IPrototypeManager _prototypeManager; -#pragma warning restore 649 + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; public override string Name => "TransformableContainer"; - private bool _transformed = false; - public bool Transformed { get => _transformed; } + private SpriteSpecifier? _initialSprite; + private string _initialName = default!; + private string _initialDescription = default!; + private ReagentPrototype? _currentReagent; - private SpriteSpecifier _initialSprite; - private string _initialName; - private string _initialDescription; - private SpriteComponent _sprite; - - private ReagentPrototype _currentReagent; + public bool Transformed { get; private set; } public override void Initialize() { base.Initialize(); - _sprite = Owner.GetComponent(); - _initialSprite = new SpriteSpecifier.Rsi(new ResourcePath(_sprite.BaseRSIPath), "icon"); + if (Owner.TryGetComponent(out SpriteComponent? sprite) && + sprite.BaseRSIPath != null) + { + _initialSprite = new SpriteSpecifier.Rsi(new ResourcePath(sprite.BaseRSIPath), "icon"); + } + _initialName = Owner.Name; _initialDescription = Owner.Description; } @@ -40,14 +40,20 @@ namespace Content.Server.GameObjects.Components.Chemistry protected override void Startup() { base.Startup(); - Owner.GetComponent().Capabilities |= SolutionCaps.FitsInDispenser;; + Owner.GetComponent().Capabilities |= SolutionCaps.FitsInDispenser; } public void CancelTransformation() { _currentReagent = null; - _transformed = false; - _sprite.LayerSetSprite(0, _initialSprite); + Transformed = false; + + if (Owner.TryGetComponent(out SpriteComponent? sprite) && + _initialSprite != null) + { + sprite.LayerSetSprite(0, _initialSprite); + } + Owner.Name = _initialName; Owner.Description = _initialDescription; } @@ -76,11 +82,16 @@ namespace Content.Server.GameObjects.Components.Chemistry !string.IsNullOrWhiteSpace(proto.SpriteReplacementPath)) { 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.Description = proto.Description; _currentReagent = proto; - _transformed = true; + Transformed = true; } } } diff --git a/Content.Server/GameObjects/Components/Command/CommunicationsConsoleComponent.cs b/Content.Server/GameObjects/Components/Command/CommunicationsConsoleComponent.cs index d982b1fb06..4a26ee6a4a 100644 --- a/Content.Server/GameObjects/Components/Command/CommunicationsConsoleComponent.cs +++ b/Content.Server/GameObjects/Components/Command/CommunicationsConsoleComponent.cs @@ -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.Shared.GameObjects.Components.Command; using Content.Shared.Interfaces.GameObjects.Components; @@ -8,6 +9,7 @@ using Robust.Server.Interfaces.Player; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; +using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Command { @@ -15,22 +17,27 @@ namespace Content.Server.GameObjects.Components.Command [ComponentReference(typeof(IActivate))] public class CommunicationsConsoleComponent : SharedCommunicationsConsoleComponent, IActivate { -#pragma warning disable 649 - [Dependency] private IEntitySystemManager _entitySystemManager; -#pragma warning restore 649 + [Dependency] private readonly IEntitySystemManager _entitySystemManager = default!; + + 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(); + [ViewVariables] + private BoundUserInterface? UserInterface => + Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) && + ui.TryGetBoundUserInterface(CommunicationsConsoleUiKey.Key, out var boundUi) + ? boundUi + : null; + public override void Initialize() { base.Initialize(); - _userInterface = Owner.GetComponent().GetBoundUserInterface(CommunicationsConsoleUiKey.Key); - _userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; - _powerReceiver = Owner.GetComponent(); + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; + } RoundEndSystem.OnRoundEndCountdownStarted += UpdateBoundInterface; RoundEndSystem.OnRoundEndCountdownCancelled += UpdateBoundInterface; @@ -39,7 +46,7 @@ namespace Content.Server.GameObjects.Components.Command private void UpdateBoundInterface() { - _userInterface.SetState(new CommunicationsConsoleInterfaceState(RoundEndSystem.ExpectedCountdownEnd)); + UserInterface?.SetState(new CommunicationsConsoleInterfaceState(RoundEndSystem.ExpectedCountdownEnd)); } private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage obj) @@ -58,12 +65,12 @@ namespace Content.Server.GameObjects.Components.Command public void OpenUserInterface(IPlayerSession session) { - _userInterface.Open(session); + UserInterface?.Open(session); } void IActivate.Activate(ActivateEventArgs eventArgs) { - if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) + if (!eventArgs.User.TryGetComponent(out IActorComponent? actor)) return; if (!Powered) diff --git a/Content.Server/GameObjects/Components/Conveyor/ConveyorComponent.cs b/Content.Server/GameObjects/Components/Conveyor/ConveyorComponent.cs index 689e3f8bea..01a29b4a05 100644 --- a/Content.Server/GameObjects/Components/Conveyor/ConveyorComponent.cs +++ b/Content.Server/GameObjects/Components/Conveyor/ConveyorComponent.cs @@ -28,10 +28,8 @@ namespace Content.Server.GameObjects.Components.Conveyor [RegisterComponent] public class ConveyorComponent : Component, IInteractUsing { -#pragma warning disable 649 [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IRobustRandom _random = default!; -#pragma warning restore 649 public override string Name => "Conveyor"; diff --git a/Content.Server/GameObjects/Components/Damage/DamageOnToolInteractComponent.cs b/Content.Server/GameObjects/Components/Damage/DamageOnToolInteractComponent.cs index 72043c215a..6a8c680fd6 100644 --- a/Content.Server/GameObjects/Components/Damage/DamageOnToolInteractComponent.cs +++ b/Content.Server/GameObjects/Components/Damage/DamageOnToolInteractComponent.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Content.Server.GameObjects.Components.Interactable; using Content.Shared.Damage; +using Content.Shared.GameObjects.Components.Damage; using Content.Shared.GameObjects.Components.Interactable; using Content.Shared.Interfaces.GameObjects.Components; using Robust.Shared.GameObjects; @@ -27,12 +28,6 @@ namespace Content.Server.GameObjects.Components.Damage serializer.DataField(ref _tools, "tools", new List()); } - public override void Initialize() - { - base.Initialize(); - Owner.EnsureComponent(); - } - public async Task InteractUsing(InteractUsingEventArgs eventArgs) { if (eventArgs.Using.TryGetComponent(out var tool)) @@ -56,7 +51,7 @@ namespace Content.Server.GameObjects.Components.Damage protected bool CallDamage(InteractUsingEventArgs eventArgs, ToolComponent tool) { - if (eventArgs.Target.TryGetComponent(out var damageable)) + if (eventArgs.Target.TryGetComponent(out var damageable)) { damageable.ChangeDamage(tool.HasQuality(ToolQuality.Welding) ? DamageType.Heat diff --git a/Content.Server/GameObjects/Components/Disposal/DisposalRouterComponent.cs b/Content.Server/GameObjects/Components/Disposal/DisposalRouterComponent.cs index 1d3662a85c..9c85698e77 100644 --- a/Content.Server/GameObjects/Components/Disposal/DisposalRouterComponent.cs +++ b/Content.Server/GameObjects/Components/Disposal/DisposalRouterComponent.cs @@ -1,4 +1,5 @@ -using Content.Server.Interfaces; +#nullable enable +using Content.Server.Interfaces; using Content.Server.Interfaces.GameObjects.Components.Items; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces.GameObjects.Components; @@ -25,22 +26,24 @@ namespace Content.Server.GameObjects.Components.Disposal [ComponentReference(typeof(IDisposalTubeComponent))] public class DisposalRouterComponent : DisposalJunctionComponent, IActivate { -#pragma warning disable 649 - [Dependency] private readonly IServerNotifyManager _notifyManager; -#pragma warning restore 649 + [Dependency] private readonly IServerNotifyManager _notifyManager = default!; public override string Name => "DisposalRouter"; [ViewVariables] - private BoundUserInterface _userInterface; - - [ViewVariables] - private HashSet _tags; + private readonly HashSet _tags = new HashSet(); [ViewVariables] public bool Anchored => - !Owner.TryGetComponent(out CollidableComponent collidable) || + !Owner.TryGetComponent(out ICollidableComponent? collidable) || 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) { var directions = ConnectableDirections(); @@ -53,15 +56,14 @@ namespace Content.Server.GameObjects.Components.Disposal return Owner.Transform.LocalRotation.GetDir(); } - public override void Initialize() { base.Initialize(); - _userInterface = Owner.GetComponent() - .GetBoundUserInterface(DisposalRouterUiKey.Key); - _userInterface.OnReceiveMessage += OnUiReceiveMessage; - _tags = new HashSet(); + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += OnUiReceiveMessage; + } UpdateUserInterface(); } @@ -73,6 +75,11 @@ namespace Content.Server.GameObjects.Components.Disposal /// A user interface message from the client. private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj) { + if (obj.Session.AttachedEntity == null) + { + return; + } + var msg = (UiActionMessage) obj.Message; if (!PlayerCanUseDisposalTagger(obj.Session.AttachedEntity)) @@ -112,10 +119,10 @@ namespace Content.Server.GameObjects.Components.Disposal /// /// Gets component data to be used to update the user interface client-side. /// - /// Returns a + /// Returns a private DisposalRouterUserInterfaceState GetUserInterfaceState() { - if(_tags == null || _tags.Count <= 0) + if(_tags.Count <= 0) { return new DisposalRouterUserInterfaceState(""); } @@ -136,7 +143,7 @@ namespace Content.Server.GameObjects.Components.Disposal private void UpdateUserInterface() { var state = GetUserInterfaceState(); - _userInterface.SetState(state); + UserInterface?.SetState(state); } private void ClickSound() @@ -150,12 +157,12 @@ namespace Content.Server.GameObjects.Components.Disposal /// Data relevant to the event such as the actor which triggered it. void IActivate.Activate(ActivateEventArgs args) { - if (!args.User.TryGetComponent(out IActorComponent actor)) + if (!args.User.TryGetComponent(out IActorComponent? actor)) { return; } - if (!args.User.TryGetComponent(out IHandsComponent hands)) + if (!args.User.TryGetComponent(out IHandsComponent? hands)) { _notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User, Loc.GetString("You have no hands.")); @@ -166,13 +173,13 @@ namespace Content.Server.GameObjects.Components.Disposal if (activeHandEntity == null) { UpdateUserInterface(); - _userInterface.Open(actor.playerSession); + UserInterface?.Open(actor.playerSession); } } public override void OnRemove() { - _userInterface.CloseAll(); + UserInterface?.CloseAll(); base.OnRemove(); } } diff --git a/Content.Server/GameObjects/Components/Disposal/DisposalTaggerComponent.cs b/Content.Server/GameObjects/Components/Disposal/DisposalTaggerComponent.cs index 3c1ab7bf81..34bb94e19b 100644 --- a/Content.Server/GameObjects/Components/Disposal/DisposalTaggerComponent.cs +++ b/Content.Server/GameObjects/Components/Disposal/DisposalTaggerComponent.cs @@ -1,4 +1,5 @@ -using Content.Server.Interfaces; +#nullable enable +using Content.Server.Interfaces; using Content.Server.Interfaces.GameObjects.Components.Items; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces.GameObjects.Components; @@ -23,35 +24,38 @@ namespace Content.Server.GameObjects.Components.Disposal [ComponentReference(typeof(IDisposalTubeComponent))] public class DisposalTaggerComponent : DisposalTransitComponent, IActivate { -#pragma warning disable 649 - [Dependency] private readonly IServerNotifyManager _notifyManager; -#pragma warning restore 649 + [Dependency] private readonly IServerNotifyManager _notifyManager = default!; public override string Name => "DisposalTagger"; - [ViewVariables] - private BoundUserInterface _userInterface; - [ViewVariables(VVAccess.ReadWrite)] private string _tag = ""; [ViewVariables] public bool Anchored => - !Owner.TryGetComponent(out CollidableComponent collidable) || + !Owner.TryGetComponent(out CollidableComponent? collidable) || 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) { holder.Tags.Add(_tag); return base.NextDirection(holder); } - public override void Initialize() { base.Initialize(); - _userInterface = Owner.GetComponent() - .GetBoundUserInterface(DisposalTaggerUiKey.Key); - _userInterface.OnReceiveMessage += OnUiReceiveMessage; + + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += OnUiReceiveMessage; + } UpdateUserInterface(); } @@ -70,7 +74,7 @@ namespace Content.Server.GameObjects.Components.Disposal //Check for correct message and ignore maleformed strings if (msg.Action == UiAction.Ok && TagRegex.IsMatch(msg.Tag)) - { + { _tag = msg.Tag; ClickSound(); } @@ -81,7 +85,7 @@ namespace Content.Server.GameObjects.Components.Disposal /// /// The player entity. /// Returns true if the entity can use the configuration interface, and false if it cannot. - 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 if (playerEntity == null) @@ -98,7 +102,7 @@ namespace Content.Server.GameObjects.Components.Disposal /// /// Gets component data to be used to update the user interface client-side. /// - /// Returns a + /// Returns a private DisposalTaggerUserInterfaceState GetUserInterfaceState() { return new DisposalTaggerUserInterfaceState(_tag); @@ -107,7 +111,7 @@ namespace Content.Server.GameObjects.Components.Disposal private void UpdateUserInterface() { var state = GetUserInterfaceState(); - _userInterface.SetState(state); + UserInterface?.SetState(state); } private void ClickSound() @@ -121,12 +125,12 @@ namespace Content.Server.GameObjects.Components.Disposal /// Data relevant to the event such as the actor which triggered it. void IActivate.Activate(ActivateEventArgs args) { - if (!args.User.TryGetComponent(out IActorComponent actor)) + if (!args.User.TryGetComponent(out IActorComponent? actor)) { return; } - if (!args.User.TryGetComponent(out IHandsComponent hands)) + if (!args.User.TryGetComponent(out IHandsComponent? hands)) { _notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User, Loc.GetString("You have no hands.")); @@ -137,14 +141,14 @@ namespace Content.Server.GameObjects.Components.Disposal if (activeHandEntity == null) { UpdateUserInterface(); - _userInterface.Open(actor.playerSession); + UserInterface?.Open(actor.playerSession); } } public override void OnRemove() { base.OnRemove(); - _userInterface.CloseAll(); + UserInterface?.CloseAll(); } } } diff --git a/Content.Server/GameObjects/Components/Disposal/DisposalUnitComponent.cs b/Content.Server/GameObjects/Components/Disposal/DisposalUnitComponent.cs index 2e420ef91e..24ca2e6ea5 100644 --- a/Content.Server/GameObjects/Components/Disposal/DisposalUnitComponent.cs +++ b/Content.Server/GameObjects/Components/Disposal/DisposalUnitComponent.cs @@ -39,10 +39,8 @@ namespace Content.Server.GameObjects.Components.Disposal [ComponentReference(typeof(IInteractUsing))] public class DisposalUnitComponent : SharedDisposalUnitComponent, IInteractHand, IInteractUsing, IDragDropOn { -#pragma warning disable 649 [Dependency] private readonly IServerNotifyManager _notifyManager = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; -#pragma warning restore 649 public override string Name => "DisposalUnit"; @@ -81,9 +79,6 @@ namespace Content.Server.GameObjects.Components.Disposal [ViewVariables] public IReadOnlyList ContainedEntities => _container.ContainedEntities; - [ViewVariables] - private BoundUserInterface _userInterface = default!; - [ViewVariables] public bool Powered => !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) { if (!Anchored) @@ -161,7 +163,7 @@ namespace Content.Server.GameObjects.Components.Disposal if (entity.TryGetComponent(out IActorComponent? actor)) { - _userInterface.Close(actor.playerSession); + UserInterface?.Close(actor.playerSession); } UpdateVisualState(); @@ -291,10 +293,10 @@ namespace Content.Server.GameObjects.Components.Disposal private void UpdateInterface() { var state = GetInterfaceState(); - _userInterface.SetState(state); + UserInterface?.SetState(state); } - private bool PlayerCanUse(IEntity player) + private bool PlayerCanUse(IEntity? player) { if (player == null) { @@ -472,9 +474,11 @@ namespace Content.Server.GameObjects.Components.Disposal base.Initialize(); _container = ContainerManagerComponent.Ensure(Name, Owner); - _userInterface = Owner.GetComponent() - .GetBoundUserInterface(DisposalUnitUiKey.Key); - _userInterface.OnReceiveMessage += OnUiReceiveMessage; + + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += OnUiReceiveMessage; + } UpdateInterface(); } @@ -513,7 +517,7 @@ namespace Content.Server.GameObjects.Components.Disposal _container.ForceRemove(entity); } - _userInterface.CloseAll(); + UserInterface?.CloseAll(); _automaticEngageToken?.Cancel(); _automaticEngageToken = null; @@ -571,7 +575,7 @@ namespace Content.Server.GameObjects.Components.Disposal return false; } - _userInterface.Open(actor.playerSession); + UserInterface?.Open(actor.playerSession); return true; } diff --git a/Content.Server/GameObjects/Components/Doors/AirlockComponent.cs b/Content.Server/GameObjects/Components/Doors/AirlockComponent.cs index 1bc53f6ab6..e33ab84758 100644 --- a/Content.Server/GameObjects/Components/Doors/AirlockComponent.cs +++ b/Content.Server/GameObjects/Components/Doors/AirlockComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Threading; using System.Threading.Tasks; using Content.Server.GameObjects.Components.Interactable; @@ -34,10 +35,7 @@ namespace Content.Server.GameObjects.Components.Doors /// private static readonly TimeSpan PowerWiresTimeout = TimeSpan.FromSeconds(5.0); - private PowerReceiverComponent _powerReceiver; - private WiresComponent _wires; - - private CancellationTokenSource _powerWiresPulsedTimerCancel; + private CancellationTokenSource _powerWiresPulsedTimerCancel = new CancellationTokenSource(); private bool _powerWiresPulsed; @@ -89,13 +87,15 @@ namespace Content.Server.GameObjects.Components.Doors private void UpdateWiresStatus() { + WiresComponent? wires; var powerLight = new StatusLightData(Color.Yellow, StatusLightState.On, "POWR"); if (PowerWiresPulsed) { powerLight = new StatusLightData(Color.Yellow, StatusLightState.BlinkingFast, "POWR"); } - else if (_wires.IsWireCut(Wires.MainPower) && - _wires.IsWireCut(Wires.BackupPower)) + else if (Owner.TryGetComponent(out wires) && + wires.IsWireCut(Wires.MainPower) && + wires.IsWireCut(Wires.BackupPower)) { powerLight = new StatusLightData(Color.Red, StatusLightState.On, "POWR"); } @@ -114,12 +114,17 @@ namespace Content.Server.GameObjects.Components.Doors var safetyStatus = new StatusLightData(Color.Red, Safety ? StatusLightState.On : StatusLightState.Off, "SAFE"); - _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); + if (!Owner.TryGetComponent(out wires)) + { + return; + } + + 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(7, powerLight); @@ -131,14 +136,30 @@ namespace Content.Server.GameObjects.Components.Doors private void UpdatePowerCutStatus() { - _powerReceiver.PowerDisabled = PowerWiresPulsed || - _wires.IsWireCut(Wires.MainPower) || - _wires.IsWireCut(Wires.BackupPower); + if (!Owner.TryGetComponent(out PowerReceiverComponent? receiver)) + { + 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() { - if (Owner.TryGetComponent(out AppearanceComponent appearance)) + if (Owner.TryGetComponent(out AppearanceComponent? appearance)) { appearance.SetData(DoorVisuals.BoltLights, BoltLightsVisible); } @@ -150,7 +171,10 @@ namespace Content.Server.GameObjects.Components.Doors { base.State = value; // 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 UpdateBoltLightStatus(); } @@ -159,29 +183,32 @@ namespace Content.Server.GameObjects.Components.Doors public override void Initialize() { base.Initialize(); - _powerReceiver = Owner.GetComponent(); - _wires = Owner.GetComponent(); - _powerReceiver.OnPowerStateChanged += PowerDeviceOnOnPowerStateChanged; - if (Owner.TryGetComponent(out AppearanceComponent appearance)) + if (Owner.TryGetComponent(out PowerReceiverComponent? receiver)) { - 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() { - if (Owner.TryGetComponent(out _powerReceiver)) + if (Owner.TryGetComponent(out PowerReceiverComponent? receiver)) { - _powerReceiver.OnPowerStateChanged -= PowerDeviceOnOnPowerStateChanged; + receiver.OnPowerStateChanged -= PowerDeviceOnOnPowerStateChanged; } 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); } @@ -192,11 +219,12 @@ namespace Content.Server.GameObjects.Components.Doors 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 @@ -276,8 +304,7 @@ namespace Content.Server.GameObjects.Components.Doors case Wires.MainPower: case Wires.BackupPower: PowerWiresPulsed = true; - _powerWiresPulsedTimerCancel?.Cancel(); - _powerWiresPulsedTimerCancel = new CancellationTokenSource(); + _powerWiresPulsedTimerCancel.Cancel(); Timer.Spawn(PowerWiresTimeout, () => PowerWiresPulsed = false, _powerWiresPulsedTimerCancel.Token); @@ -381,7 +408,8 @@ namespace Content.Server.GameObjects.Components.Doors private bool IsPowered() { - return _powerReceiver.Powered; + return !Owner.TryGetComponent(out PowerReceiverComponent? receiver) + || receiver.Powered; } public async Task InteractUsing(InteractUsingEventArgs eventArgs) @@ -392,11 +420,12 @@ namespace Content.Server.GameObjects.Components.Doors if (tool.HasQuality(ToolQuality.Cutting) || 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; } } diff --git a/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs b/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs index 8df3c2601c..d4579037db 100644 --- a/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs +++ b/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Linq; using System.Threading; using Content.Server.GameObjects.Components.Access; @@ -44,10 +45,7 @@ namespace Content.Server.GameObjects.Components.Doors protected const float AutoCloseDelay = 5; protected float CloseSpeed = AutoCloseDelay; - private AirtightComponent airtightComponent; - private ICollidableComponent _collidableComponent; - private AppearanceComponent _appearance; - private CancellationTokenSource _cancellationTokenSource; + private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); private static readonly TimeSpan CloseTimeOne = TimeSpan.FromSeconds(0.3f); 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); } - public override void Initialize() - { - base.Initialize(); - - airtightComponent = Owner.GetComponent(); - _collidableComponent = Owner.GetComponent(); - _appearance = Owner.GetComponent(); - _cancellationTokenSource = new CancellationTokenSource(); - } - public override void OnRemove() { _cancellationTokenSource?.Cancel(); - _collidableComponent = null; - _appearance = null; base.OnRemove(); } @@ -104,7 +90,6 @@ namespace Content.Server.GameObjects.Components.Doors ActivateImpl(eventArgs); } - void ICollideBehavior.CollideWith(IEntity entity) { if (State != DoorState.Closed) @@ -135,8 +120,10 @@ namespace Content.Server.GameObjects.Components.Doors private void SetAppearance(DoorVisualState state) { - if (_appearance != null || Owner.TryGetComponent(out _appearance)) - _appearance.SetData(DoorVisuals.VisualState, state); + if (Owner.TryGetComponent(out AppearanceComponent? appearance)) + { + appearance.SetData(DoorVisuals.VisualState, state); + } } public virtual bool CanOpen() @@ -147,7 +134,7 @@ namespace Content.Server.GameObjects.Components.Doors public bool CanOpen(IEntity user) { if (!CanOpen()) return false; - if (!Owner.TryGetComponent(out AccessReader accessReader)) + if (!Owner.TryGetComponent(out AccessReader? accessReader)) { return true; } @@ -165,7 +152,7 @@ namespace Content.Server.GameObjects.Components.Doors Open(); - if (user.TryGetComponent(out HandsComponent hands) && hands.Count == 0) + if (user.TryGetComponent(out HandsComponent? hands) && hands.Count == 0) { EntitySystem.Get().PlayFromEntity("/Audio/Effects/bang.ogg", Owner, AudioParams.Default.WithVolume(-2)); @@ -181,15 +168,22 @@ namespace Content.Server.GameObjects.Components.Doors State = DoorState.Opening; SetAppearance(DoorVisualState.Opening); - if (_occludes && Owner.TryGetComponent(out OccluderComponent occluder)) + if (_occludes && Owner.TryGetComponent(out OccluderComponent? occluder)) { occluder.Enabled = false; } Timer.Spawn(OpenTimeOne, async () => { - airtightComponent.AirBlocked = false; - _collidableComponent.Hard = false; + if (Owner.TryGetComponent(out AirtightComponent? airtight)) + { + airtight.AirBlocked = false; + } + + if (Owner.TryGetComponent(out ICollidableComponent? collidable)) + { + collidable.Hard = false; + } await Timer.Delay(OpenTimeTwo, _cancellationTokenSource.Token); @@ -208,7 +202,7 @@ namespace Content.Server.GameObjects.Components.Doors public bool CanClose(IEntity user) { if (!CanClose()) return false; - if (!Owner.TryGetComponent(out AccessReader accessReader)) + if (!Owner.TryGetComponent(out AccessReader? accessReader)) { return true; } @@ -229,18 +223,22 @@ namespace Content.Server.GameObjects.Components.Doors private void CheckCrush() { + if (!Owner.TryGetComponent(out ICollidableComponent? body)) + { + return; + } + // Check if collides with something - var collidesWith = _collidableComponent.GetCollidingEntities(Vector2.Zero, false); + var collidesWith = body.GetCollidingEntities(Vector2.Zero, false); if (collidesWith.Count() != 0) { // Crush bool hitSomeone = false; foreach (var e in collidesWith) { - if (!e.TryGetComponent(out StunnableComponent stun) - || !e.TryGetComponent(out IDamageableComponent damage) - || !e.TryGetComponent(out ICollidableComponent otherBody) - || !Owner.TryGetComponent(out ICollidableComponent body)) + if (!e.TryGetComponent(out StunnableComponent? stun) + || !e.TryGetComponent(out IDamageableComponent? damage) + || !e.TryGetComponent(out ICollidableComponent? otherBody)) continue; var percentage = otherBody.WorldAABB.IntersectPercentage(body.WorldAABB); @@ -264,7 +262,8 @@ namespace Content.Server.GameObjects.Components.Doors public bool Close() { bool shouldCheckCrush = false; - if (_collidableComponent.IsColliding(Vector2.Zero, false)) + + if (Owner.TryGetComponent(out ICollidableComponent? collidable) && collidable.IsColliding(Vector2.Zero, false)) { if (Safety) return false; @@ -276,7 +275,7 @@ namespace Content.Server.GameObjects.Components.Doors State = DoorState.Closing; OpenTimeCounter = 0; SetAppearance(DoorVisualState.Closing); - if (_occludes && Owner.TryGetComponent(out OccluderComponent occluder)) + if (_occludes && Owner.TryGetComponent(out OccluderComponent? occluder)) { occluder.Enabled = true; } @@ -288,8 +287,15 @@ namespace Content.Server.GameObjects.Components.Doors CheckCrush(); } - airtightComponent.AirBlocked = true; - _collidableComponent.Hard = true; + if (Owner.TryGetComponent(out AirtightComponent? airtight)) + { + airtight.AirBlocked = true; + } + + if (Owner.TryGetComponent(out ICollidableComponent? body)) + { + body.Hard = true; + } await Timer.Delay(CloseTimeTwo, _cancellationTokenSource.Token); diff --git a/Content.Server/GameObjects/Components/Fluids/BucketComponent.cs b/Content.Server/GameObjects/Components/Fluids/BucketComponent.cs index 11c3281a94..4f9afed4af 100644 --- a/Content.Server/GameObjects/Components/Fluids/BucketComponent.cs +++ b/Content.Server/GameObjects/Components/Fluids/BucketComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Threading.Tasks; using Content.Server.GameObjects.Components.Chemistry; using Content.Shared.Chemistry; @@ -19,23 +20,27 @@ namespace Content.Server.GameObjects.Components.Fluids [RegisterComponent] public class BucketComponent : Component, IInteractUsing { -#pragma warning disable 649 - [Dependency] private readonly ILocalizationManager _localizationManager; -#pragma warning restore 649 + [Dependency] private readonly ILocalizationManager _localizationManager = default!; public override string Name => "Bucket"; public ReagentUnit MaxVolume { - get => _contents.MaxVolume; - set => _contents.MaxVolume = value; + get => Owner.TryGetComponent(out SolutionComponent? solution) ? solution.MaxVolume : ReagentUnit.Zero; + 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; /// public override void ExposeData(ObjectSerializer serializer) @@ -47,15 +52,20 @@ namespace Content.Server.GameObjects.Components.Fluids public override void Initialize() { base.Initialize(); - _contents = Owner.GetComponent(); + Owner.EnsureComponent(); } private bool TryGiveToMop(MopComponent mopComponent) { + if (!Owner.TryGetComponent(out SolutionComponent? contents)) + { + return false; + } + // Let's fill 'er up // 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 solution = _contents.SplitSolution(transferAmount); + var solution = contents.SplitSolution(transferAmount); if (!mopComponent.Contents.TryAddSolution(solution) || mopComponent.CurrentVolume == 0) { return false; @@ -73,7 +83,12 @@ namespace Content.Server.GameObjects.Components.Fluids public async Task 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; } @@ -97,7 +112,7 @@ namespace Content.Server.GameObjects.Components.Fluids } var solution = mopComponent.Contents.SplitSolution(transferAmount); - if (!_contents.TryAddSolution(solution)) + if (!contents.TryAddSolution(solution)) { //This really shouldn't happen throw new InvalidOperationException(); diff --git a/Content.Server/GameObjects/Components/Fluids/PuddleComponent.cs b/Content.Server/GameObjects/Components/Fluids/PuddleComponent.cs index 598ee20754..cc598e7455 100644 --- a/Content.Server/GameObjects/Components/Fluids/PuddleComponent.cs +++ b/Content.Server/GameObjects/Components/Fluids/PuddleComponent.cs @@ -126,18 +126,25 @@ namespace Content.Server.GameObjects.Components.Fluids _contents.Initialize(); } - _snapGrid = Owner.GetComponent(); + _snapGrid = Owner.EnsureComponent(); // Smaller than 1m^3 for now but realistically this shouldn't be hit MaxVolume = ReagentUnit.New(1000); // Random sprite state set server-side so it's consistent across all clients - _spriteComponent = Owner.GetComponent(); + _spriteComponent = Owner.EnsureComponent(); + var robustRandom = IoCManager.Resolve(); var randomVariant = robustRandom.Next(0, _spriteVariants - 1); - var baseName = new ResourcePath(_spriteComponent.BaseRSIPath).FilenameWithoutExtension; - _spriteComponent.LayerSetState(0, $"{baseName}-{randomVariant}"); // TODO: Remove hardcode + if (_spriteComponent.BaseRSIPath != null) + { + var baseName = new ResourcePath(_spriteComponent.BaseRSIPath).FilenameWithoutExtension; + + _spriteComponent.LayerSetState(0, $"{baseName}-{randomVariant}"); // TODO: Remove hardcode + + } + // UpdateAppearance should get called soon after this so shouldn't need to call Dirty() here UpdateStatus(); diff --git a/Content.Server/GameObjects/Components/Fluids/SprayComponent.cs b/Content.Server/GameObjects/Components/Fluids/SprayComponent.cs index ffb9cbdaa0..d1e9c6f098 100644 --- a/Content.Server/GameObjects/Components/Fluids/SprayComponent.cs +++ b/Content.Server/GameObjects/Components/Fluids/SprayComponent.cs @@ -16,10 +16,9 @@ namespace Content.Server.GameObjects.Components.Fluids [RegisterComponent] class SprayComponent : Component, IAfterInteract { -#pragma warning disable 649 [Dependency] private readonly IServerNotifyManager _notifyManager = default!; [Dependency] private readonly IServerEntityManager _serverEntityManager = default!; -#pragma warning restore 649 + public override string Name => "Spray"; private ReagentUnit _transferAmount; diff --git a/Content.Server/GameObjects/Components/GUI/HandsComponent.cs b/Content.Server/GameObjects/Components/GUI/HandsComponent.cs index 69fe0be734..ade7beee0d 100644 --- a/Content.Server/GameObjects/Components/GUI/HandsComponent.cs +++ b/Content.Server/GameObjects/Components/GUI/HandsComponent.cs @@ -37,9 +37,7 @@ namespace Content.Server.GameObjects.Components.GUI [ComponentReference(typeof(ISharedHandsComponent))] public class HandsComponent : SharedHandsComponent, IHandsComponent, IBodyPartAdded, IBodyPartRemoved { -#pragma warning disable 649 [Dependency] private readonly IEntitySystemManager _entitySystemManager = default!; -#pragma warning restore 649 private string? _activeHand; private uint _nextHand; diff --git a/Content.Server/GameObjects/Components/GUI/HumanInventoryControllerComponent.cs b/Content.Server/GameObjects/Components/GUI/HumanInventoryControllerComponent.cs index 80eb1e9d75..9a72da1520 100644 --- a/Content.Server/GameObjects/Components/GUI/HumanInventoryControllerComponent.cs +++ b/Content.Server/GameObjects/Components/GUI/HumanInventoryControllerComponent.cs @@ -21,7 +21,7 @@ namespace Content.Server.GameObjects.Components.GUI { base.Initialize(); - _inventory = Owner.GetComponent(); + _inventory = Owner.EnsureComponent(); } bool IInventoryController.CanEquip(Slots slot, IEntity entity, bool flagsCheck, out string reason) diff --git a/Content.Server/GameObjects/Components/GUI/StrippableComponent.cs b/Content.Server/GameObjects/Components/GUI/StrippableComponent.cs index 0363fee424..38270dcf46 100644 --- a/Content.Server/GameObjects/Components/GUI/StrippableComponent.cs +++ b/Content.Server/GameObjects/Components/GUI/StrippableComponent.cs @@ -1,11 +1,10 @@ -using System; +#nullable enable using System.Collections.Generic; using System.Threading; using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.EntitySystems.DoAfter; using Content.Server.Interfaces; using Content.Shared.GameObjects.Components.GUI; -using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces.GameObjects.Components; using Robust.Server.GameObjects.Components.UserInterface; @@ -16,7 +15,6 @@ using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Localization; -using Robust.Shared.Log; using Robust.Shared.ViewVariables; using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines; @@ -25,27 +23,33 @@ namespace Content.Server.GameObjects.Components.GUI [RegisterComponent] public sealed class StrippableComponent : SharedStrippableComponent, IDragDrop { - [Dependency] private IServerNotifyManager _notifyManager = default!; + [Dependency] private readonly IServerNotifyManager _notifyManager = default!; public const float StripDelay = 2f; [ViewVariables] - private BoundUserInterface _userInterface; - - private InventoryComponent _inventoryComponent; - private HandsComponent _handsComponent; + private BoundUserInterface? UserInterface => + Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) && + ui.TryGetBoundUserInterface(StrippingUiKey.Key, out var boundUi) + ? boundUi + : null; public override void Initialize() { base.Initialize(); - _userInterface = Owner.GetComponent().GetBoundUserInterface(StrippingUiKey.Key); - _userInterface.OnReceiveMessage += HandleUserInterfaceMessage; + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += HandleUserInterfaceMessage; + } - _inventoryComponent = Owner.GetComponent(); - _handsComponent = Owner.GetComponent(); + Owner.EnsureComponent(); + Owner.EnsureComponent(); - _inventoryComponent.OnItemChanged += UpdateSubscribed; + if (Owner.TryGetComponent(out InventoryComponent? inventory)) + { + inventory.OnItemChanged += UpdateSubscribed; + } // Initial update. UpdateSubscribed(); @@ -53,10 +57,15 @@ namespace Content.Server.GameObjects.Components.GUI private void UpdateSubscribed() { + if (UserInterface == null) + { + return; + } + var inventory = GetInventorySlots(); var hands = GetHandSlots(); - _userInterface.SetState(new StrippingBoundUserInterfaceState(inventory, hands)); + UserInterface.SetState(new StrippingBoundUserInterfaceState(inventory, hands)); } public bool CanDragDrop(DragDropEventArgs eventArgs) @@ -67,7 +76,7 @@ namespace Content.Server.GameObjects.Components.GUI 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); return true; @@ -77,9 +86,14 @@ namespace Content.Server.GameObjects.Components.GUI { var dictionary = new Dictionary(); - 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; @@ -89,9 +103,14 @@ namespace Content.Server.GameObjects.Components.GUI { var dictionary = new Dictionary(); - 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; @@ -99,7 +118,7 @@ namespace Content.Server.GameObjects.Components.GUI private void OpenUserInterface(IPlayerSession session) { - _userInterface.Open(session); + UserInterface?.Open(session); } /// @@ -336,7 +355,7 @@ namespace Content.Server.GameObjects.Components.GUI private void HandleUserInterfaceMessage(ServerBoundUserInterfaceMessage obj) { 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; diff --git a/Content.Server/GameObjects/Components/Gravity/GravityGeneratorComponent.cs b/Content.Server/GameObjects/Components/Gravity/GravityGeneratorComponent.cs index 55e6acfe92..7aa3a9df81 100644 --- a/Content.Server/GameObjects/Components/Gravity/GravityGeneratorComponent.cs +++ b/Content.Server/GameObjects/Components/Gravity/GravityGeneratorComponent.cs @@ -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.Interactable; using Content.Server.GameObjects.Components.Power.ApcNetComponents; -using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces; using Content.Shared.GameObjects.Components.Gravity; using Content.Shared.GameObjects.Components.Interactable; @@ -22,11 +22,6 @@ namespace Content.Server.GameObjects.Components.Gravity [RegisterComponent] public class GravityGeneratorComponent : SharedGravityGeneratorComponent, IInteractUsing, IBreakAct, IInteractHand { - private BoundUserInterface _userInterface; - - private PowerReceiverComponent _powerReceiver; - - private SpriteComponent _sprite; private bool _switchedOn; @@ -34,7 +29,7 @@ namespace Content.Server.GameObjects.Components.Gravity private GravityGeneratorStatus _status; - public bool Powered => _powerReceiver.Powered; + public bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered; public bool SwitchedOn => _switchedOn; @@ -64,15 +59,21 @@ namespace Content.Server.GameObjects.Components.Gravity 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() { base.Initialize(); - _userInterface = Owner.GetComponent() - .GetBoundUserInterface(GravityGeneratorUiKey.Key); - _userInterface.OnReceiveMessage += HandleUIMessage; - _powerReceiver = Owner.GetComponent(); - _sprite = Owner.GetComponent(); + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += HandleUIMessage; + } + _switchedOn = true; _intact = true; _status = GravityGeneratorStatus.On; @@ -101,7 +102,7 @@ namespace Content.Server.GameObjects.Components.Gravity public async Task InteractUsing(InteractUsingEventArgs eventArgs) { - if (!eventArgs.Using.TryGetComponent(out WelderComponent tool)) + if (!eventArgs.Using.TryGetComponent(out WelderComponent? tool)) return false; if (!await tool.UseTool(eventArgs.User, Owner, 2f, ToolQuality.Welding, 5f)) @@ -150,7 +151,7 @@ namespace Content.Server.GameObjects.Components.Gravity switch (message.Message) { case GeneratorStatusRequestMessage _: - _userInterface.SetState(new GeneratorState(Status == GravityGeneratorStatus.On)); + UserInterface?.SetState(new GeneratorState(Status == GravityGeneratorStatus.On)); break; case SwitchGeneratorMessage msg: _switchedOn = msg.On; @@ -163,35 +164,51 @@ namespace Content.Server.GameObjects.Components.Gravity private void OpenUserInterface(IPlayerSession playerSession) { - _userInterface.Open(playerSession); + UserInterface?.Open(playerSession); } private void MakeBroken() { _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() { _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() { _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() { _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); + } } } diff --git a/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs b/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs index f73f8827c4..833db0d87b 100644 --- a/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs +++ b/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Linq; using Content.Server.GameObjects.Components.Mobs; using Content.Server.Interfaces; @@ -34,12 +35,8 @@ namespace Content.Server.GameObjects.Components.Instruments IUse, IThrown { - -#pragma warning disable 649 - [Dependency] private readonly IServerNotifyManager _notifyManager; - - [Dependency] private readonly IGameTiming _gameTiming; -#pragma warning restore 649 + [Dependency] private readonly IServerNotifyManager _notifyManager = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; 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. /// [ViewVariables] - private IPlayerSession _instrumentPlayer; + private IPlayerSession? _instrumentPlayer; private bool _handheld; @@ -72,9 +69,6 @@ namespace Content.Server.GameObjects.Components.Instruments [ViewVariables] private int _midiEventCount = 0; - [ViewVariables] - private BoundUserInterface _userInterface; - /// /// Whether the instrument is an item which can be held or not. /// @@ -95,7 +89,7 @@ namespace Content.Server.GameObjects.Components.Instruments } } - public IPlayerSession InstrumentPlayer + public IPlayerSession? InstrumentPlayer { get => _instrumentPlayer; private set @@ -108,11 +102,18 @@ namespace Content.Server.GameObjects.Components.Instruments _instrumentPlayer = value; 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; InstrumentPlayer = null; @@ -122,8 +123,11 @@ namespace Content.Server.GameObjects.Components.Instruments public override void Initialize() { base.Initialize(); - _userInterface = Owner.GetComponent().GetBoundUserInterface(InstrumentUiKey.Key); - _userInterface.OnClosed += UserInterfaceOnClosed; + + if (UserInterface != null) + { + UserInterface.OnClosed += UserInterfaceOnClosed; + } } public override void ExposeData(ObjectSerializer serializer) @@ -137,14 +141,14 @@ namespace Content.Server.GameObjects.Components.Instruments 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); switch (message) { case InstrumentMidiEventMessage midiEventMsg: - if (!Playing || session != _instrumentPlayer) return; + if (!Playing || session != _instrumentPlayer || InstrumentPlayer == null) return; var send = true; @@ -231,7 +235,7 @@ namespace Content.Server.GameObjects.Components.Instruments Clean(); SendNetworkMessage(new InstrumentStopMidiMessage()); InstrumentPlayer = null; - _userInterface.CloseAll(); + UserInterface?.CloseAll(); } public void Thrown(ThrownEventArgs eventArgs) @@ -239,7 +243,7 @@ namespace Content.Server.GameObjects.Components.Instruments Clean(); SendNetworkMessage(new InstrumentStopMidiMessage()); InstrumentPlayer = null; - _userInterface.CloseAll(); + UserInterface?.CloseAll(); } public void HandSelected(HandSelectedEventArgs eventArgs) @@ -255,12 +259,12 @@ namespace Content.Server.GameObjects.Components.Instruments { Clean(); SendNetworkMessage(new InstrumentStopMidiMessage()); - _userInterface.CloseAll(); + UserInterface?.CloseAll(); } 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; @@ -270,7 +274,7 @@ namespace Content.Server.GameObjects.Components.Instruments 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) { @@ -291,7 +295,7 @@ namespace Content.Server.GameObjects.Components.Instruments private void OpenUserInterface(IPlayerSession session) { - _userInterface.Open(session); + UserInterface?.Open(session); } public override void Update(float delta) @@ -302,7 +306,7 @@ namespace Content.Server.GameObjects.Components.Instruments { InstrumentPlayer = null; Clean(); - _userInterface.CloseAll(); + UserInterface?.CloseAll(); } if ((_batchesDropped >= MaxMidiBatchDropped @@ -314,9 +318,9 @@ namespace Content.Server.GameObjects.Components.Instruments SendNetworkMessage(new InstrumentStopMidiMessage()); Playing = false; - _userInterface.CloseAll(); + UserInterface?.CloseAll(); - if (mob.TryGetComponent(out StunnableComponent stun)) + if (mob != null && mob.TryGetComponent(out StunnableComponent? stun)) { stun.Stun(1); Clean(); diff --git a/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs b/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs index e1a0bd2415..f581c1957e 100644 --- a/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs @@ -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.Items.Clothing; using Content.Server.GameObjects.Components.Items.Storage; @@ -29,25 +30,20 @@ namespace Content.Server.GameObjects.Components.Interactable [RegisterComponent] internal sealed class HandheldLightComponent : SharedHandheldLightComponent, IUse, IExamine, IInteractUsing, IMapInit { -#pragma warning disable 649 - [Dependency] private readonly ISharedNotifyManager _notifyManager; - [Dependency] private readonly ILocalizationManager _localizationManager; -#pragma warning restore 649 + [Dependency] private readonly ISharedNotifyManager _notifyManager = default!; + [Dependency] private readonly ILocalizationManager _localizationManager = default!; [ViewVariables(VVAccess.ReadWrite)] public float Wattage { get; set; } = 10; - [ViewVariables] private ContainerSlot _cellContainer; - private PointLightComponent _pointLight; - private SpriteComponent _spriteComponent; - private ClothingComponent _clothingComponent; + [ViewVariables] private ContainerSlot _cellContainer = default!; [ViewVariables] - private BatteryComponent Cell + private BatteryComponent? Cell { get { if (_cellContainer.ContainedEntity == null) return null; - _cellContainer.ContainedEntity.TryGetComponent(out BatteryComponent cell); + _cellContainer.ContainedEntity.TryGetComponent(out BatteryComponent? cell); return cell; } } @@ -98,11 +94,10 @@ namespace Content.Server.GameObjects.Components.Interactable { base.Initialize(); - _pointLight = Owner.GetComponent(); - _spriteComponent = Owner.GetComponent(); - Owner.TryGetComponent(out _clothingComponent); + Owner.EnsureComponent(); _cellContainer = ContainerManagerComponent.Ensure("flashlight_cell_container", Owner, out _); + Dirty(); } @@ -179,11 +174,19 @@ namespace Content.Server.GameObjects.Components.Interactable private void SetState(bool on) { - _spriteComponent.LayerSetVisible(1, on); - _pointLight.Enabled = on; - if (_clothingComponent != null) + if (Owner.TryGetComponent(out SpriteComponent? sprite)) { - _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; } - if (!user.TryGetComponent(out HandsComponent hands)) + if (!user.TryGetComponent(out HandsComponent? hands)) { return; } diff --git a/Content.Server/GameObjects/Components/Interactable/WelderComponent.cs b/Content.Server/GameObjects/Components/Interactable/WelderComponent.cs index 785e19e6b0..7f37eef2e5 100644 --- a/Content.Server/GameObjects/Components/Interactable/WelderComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/WelderComponent.cs @@ -29,10 +29,8 @@ namespace Content.Server.GameObjects.Components.Interactable [ComponentReference(typeof(IToolComponent))] public class WelderComponent : ToolComponent, IExamine, IUse, ISuicideAct, ISolutionChange { -#pragma warning disable 649 [Dependency] private readonly IEntitySystemManager _entitySystemManager = default!; [Dependency] private readonly IServerNotifyManager _notifyManager = default!; -#pragma warning restore 649 public override string Name => "Welder"; public override uint? NetID => ContentNetIDs.WELDER; diff --git a/Content.Server/GameObjects/Components/Items/FloorTileItemComponent.cs b/Content.Server/GameObjects/Components/Items/FloorTileItemComponent.cs index f15948fc22..4bab06757b 100644 --- a/Content.Server/GameObjects/Components/Items/FloorTileItemComponent.cs +++ b/Content.Server/GameObjects/Components/Items/FloorTileItemComponent.cs @@ -21,10 +21,8 @@ namespace Content.Server.GameObjects.Components.Items #pragma warning restore 649 public override string Name => "FloorTile"; - private StackComponent _stack; private string _outputTile; - public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); @@ -34,18 +32,20 @@ namespace Content.Server.GameObjects.Components.Items public override void Initialize() { base.Initialize(); - _stack = Owner.GetComponent(); + Owner.EnsureComponent(); } + public void AfterInteract(AfterInteractEventArgs eventArgs) { if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return; + if (!Owner.TryGetComponent(out StackComponent stack)) return; var attacked = eventArgs.Target; var mapGrid = _mapManager.GetGrid(eventArgs.ClickLocation.GridID); var tile = mapGrid.GetTileRef(eventArgs.ClickLocation); 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]; mapGrid.SetTile(eventArgs.ClickLocation, new Tile(desiredTile.TileId)); diff --git a/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs index 8d6f4650ae..719c361083 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs @@ -37,10 +37,8 @@ namespace Content.Server.GameObjects.Components.Items.Storage public class ServerStorageComponent : SharedStorageComponent, IInteractUsing, IUse, IActivate, IStorageComponent, IDestroyAct, IExAct, IDragDrop { -#pragma warning disable 649 [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; -#pragma warning restore 649 private const string LoggerName = "Storage"; diff --git a/Content.Server/GameObjects/Components/Kitchen/MicrowaveComponent.cs b/Content.Server/GameObjects/Components/Kitchen/MicrowaveComponent.cs index 470fb19ec6..a3e049510c 100644 --- a/Content.Server/GameObjects/Components/Kitchen/MicrowaveComponent.cs +++ b/Content.Server/GameObjects/Components/Kitchen/MicrowaveComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -39,25 +40,19 @@ namespace Content.Server.GameObjects.Components.Kitchen [ComponentReference(typeof(IActivate))] public class MicrowaveComponent : SharedMicrowaveComponent, IActivate, IInteractUsing, ISolutionChange, ISuicideAct { -#pragma warning disable 649 - [Dependency] private readonly IEntityManager _entityManager; - [Dependency] private readonly RecipeManager _recipeManager; - [Dependency] private readonly IServerNotifyManager _notifyManager; -#pragma warning restore 649 + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly RecipeManager _recipeManager = default!; + [Dependency] private readonly IServerNotifyManager _notifyManager = default!; #region YAMLSERIALIZE private int _cookTimeDefault; private int _cookTimeMultiplier; //For upgrades and stuff I guess? - private string _badRecipeName; - private string _startCookingSound; - private string _cookingCompleteSound; + private string _badRecipeName = ""; + private string _startCookingSound = ""; + private string _cookingCompleteSound = ""; #endregion -#region VIEWVARIABLES - [ViewVariables] - private SolutionComponent _solution; - - [ViewVariables] +[ViewVariables] private bool _busy = false; /// @@ -67,20 +62,23 @@ namespace Content.Server.GameObjects.Components.Kitchen /// [ViewVariables] private uint _currentCookTimerTime = 1; -#endregion - private bool _powered => _powerReceiver.Powered; - private bool _hasContents => _solution.ReagentList.Count > 0 || _storage.ContainedEntities.Count > 0; + private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered; + private bool _hasContents => Owner.TryGetComponent(out SolutionComponent? solution) && (solution.ReagentList.Count > 0 || _storage.ContainedEntities.Count > 0); private bool _uiDirty = true; private bool _lostPower = false; private int _currentCookTimeButtonIndex = 0; void ISolutionChange.SolutionChanged(SolutionChangeEventArgs eventArgs) => _uiDirty = true; - private AudioSystem _audioSystem; - private AppearanceComponent _appearance; - private PowerReceiverComponent _powerReceiver; - private BoundUserInterface _userInterface; - private Container _storage; + private AudioSystem _audioSystem = default!; + private Container _storage = default!; + + [ViewVariables] + private BoundUserInterface? UserInterface => + Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) && + ui.TryGetBoundUserInterface(MicrowaveUiKey.Key, out var boundUi) + ? boundUi + : null; public override void ExposeData(ObjectSerializer serializer) { @@ -95,22 +93,21 @@ namespace Content.Server.GameObjects.Components.Kitchen public override void Initialize() { base.Initialize(); - _solution ??= Owner.TryGetComponent(out SolutionComponent solutionComponent) - ? solutionComponent - : Owner.AddComponent(); + + Owner.EnsureComponent(); _storage = ContainerManagerComponent.Ensure("microwave_entity_container", Owner, out var existed); - _appearance = Owner.GetComponent(); - _powerReceiver = Owner.GetComponent(); _audioSystem = EntitySystem.Get(); - _userInterface = Owner.GetComponent() - .GetBoundUserInterface(MicrowaveUiKey.Key); - _userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; + + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; + } } private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage message) { - if (!_powered || _busy) + if (!Powered || _busy) { return; } @@ -158,13 +155,13 @@ namespace Content.Server.GameObjects.Components.Kitchen public void OnUpdate() { - if (!_powered) + if (!Powered) { //TODO:If someone cuts power currently, microwave magically keeps going. FIX IT! SetAppearance(MicrowaveVisualState.Idle); } - if (_busy && !_powered) + if (_busy && !Powered) { //we lost power while we were cooking/busy! _lostPower = true; @@ -174,11 +171,11 @@ namespace Content.Server.GameObjects.Components.Kitchen _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(), _busy, _currentCookTimeButtonIndex, @@ -190,26 +187,26 @@ namespace Content.Server.GameObjects.Components.Kitchen 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) { - if (!eventArgs.User.TryGetComponent(out IActorComponent actor) || !_powered) + if (!eventArgs.User.TryGetComponent(out IActorComponent? actor) || !Powered) { return; } + _uiDirty = true; - _userInterface.Open(actor.playerSession); + UserInterface?.Open(actor.playerSession); } public async Task InteractUsing(InteractUsingEventArgs eventArgs) { - if (!_powered) + if (!Powered) { _notifyManager.PopupMessage(Owner.Transform.GridPosition, eventArgs.User, Loc.GetString("It has no power!")); @@ -232,8 +229,13 @@ namespace Content.Server.GameObjects.Components.Kitchen return false; } + if (!Owner.TryGetComponent(out SolutionComponent? solution)) + { + return false; + } + //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 { _notifyManager.PopupMessage(Owner.Transform.GridPosition, eventArgs.User, @@ -243,7 +245,7 @@ namespace Content.Server.GameObjects.Components.Kitchen //Move units from attackSolution to targetSolution var removedSolution = attackSolution.SplitSolution(realTransferAmount); - if (!_solution.TryAddSolution(removedSolution)) + if (!solution.TryAddSolution(removedSolution)) { return false; } @@ -280,6 +282,11 @@ namespace Content.Server.GameObjects.Components.Kitchen var solidsDict = new Dictionary(); foreach(var item in _storage.ContainedEntities) { + if (item.Prototype == null) + { + continue; + } + if(solidsDict.ContainsKey(item.Prototype.ID)) { solidsDict[item.Prototype.ID]++; @@ -303,7 +310,7 @@ namespace Content.Server.GameObjects.Components.Kitchen } // Check recipes - FoodRecipePrototype recipeToCook = null; + FoodRecipePrototype? recipeToCook = null; foreach (var r in _recipeManager.Recipes.Where(r => CanSatisfyRecipe(r, solidsDict) == MicrowaveSuccessState.RecipePass)) { recipeToCook = r; @@ -330,7 +337,7 @@ namespace Content.Server.GameObjects.Components.Kitchen { if (goodMeal) { - SubtractContents(recipeToCook); + SubtractContents(recipeToCook!); } else { @@ -357,12 +364,18 @@ namespace Content.Server.GameObjects.Components.Kitchen private void VaporizeReagents() { - _solution.RemoveAllSolution(); + if (Owner.TryGetComponent(out SolutionComponent? solution)) + { + solution.RemoveAllSolution(); + } } 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() @@ -395,9 +408,14 @@ namespace Content.Server.GameObjects.Components.Kitchen private void SubtractContents(FoodRecipePrototype recipe) { + if (!Owner.TryGetComponent(out SolutionComponent? solution)) + { + return; + } + 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) @@ -406,6 +424,11 @@ namespace Content.Server.GameObjects.Components.Kitchen { foreach (var item in _storage.ContainedEntities) { + if (item.Prototype == null) + { + continue; + } + if (item.Prototype.ID == recipeSolid.Key) { _storage.Remove(item); @@ -420,9 +443,14 @@ namespace Content.Server.GameObjects.Components.Kitchen private MicrowaveSuccessState CanSatisfyRecipe(FoodRecipePrototype recipe, Dictionary solids) { + if (!Owner.TryGetComponent(out SolutionComponent? solution)) + { + return MicrowaveSuccessState.RecipeFail; + } + 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; } diff --git a/Content.Server/GameObjects/Components/MagicMirrorComponent.cs b/Content.Server/GameObjects/Components/MagicMirrorComponent.cs index e14b07384c..c03126cf9f 100644 --- a/Content.Server/GameObjects/Components/MagicMirrorComponent.cs +++ b/Content.Server/GameObjects/Components/MagicMirrorComponent.cs @@ -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.Interfaces; using Content.Shared.Interfaces.GameObjects.Components; @@ -8,6 +9,7 @@ using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.Localization; using Robust.Shared.Maths; +using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components { @@ -15,19 +17,41 @@ namespace Content.Server.GameObjects.Components [ComponentReference(typeof(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() { base.Initialize(); - _userInterface = Owner.GetComponent() - .GetBoundUserInterface(MagicMirrorUiKey.Key); - _userInterface.OnReceiveMessage += OnUiReceiveMessage; + + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += OnUiReceiveMessage; + } + } + + public override void OnRemove() + { + if (UserInterface != null) + { + UserInterface.OnReceiveMessage -= OnUiReceiveMessage; + } + + base.OnRemove(); } 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; } @@ -70,23 +94,23 @@ namespace Content.Server.GameObjects.Components public void Activate(ActivateEventArgs eventArgs) { - if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) + if (!eventArgs.User.TryGetComponent(out IActorComponent? actor)) { 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!")); return; } - _userInterface.Open(actor.playerSession); + UserInterface?.Open(actor.playerSession); var msg = new MagicMirrorInitialDataMessage(looks.Appearance.HairColor, looks.Appearance.FacialHairColor, looks.Appearance.HairStyleName, looks.Appearance.FacialHairStyleName); - _userInterface.SendMessage(msg, actor.playerSession); + UserInterface?.SendMessage(msg, actor.playerSession); } } } diff --git a/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs b/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs index d50513e374..d16d821e78 100644 --- a/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs +++ b/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Collections.Generic; using Content.Server.GameObjects.Components.Power.ApcNetComponents; using Content.Server.GameObjects.EntitySystems; @@ -16,6 +17,7 @@ using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Maths; using Content.Shared.Damage; using Robust.Shared.Localization; +using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Medical { @@ -23,29 +25,34 @@ namespace Content.Server.GameObjects.Components.Medical [ComponentReference(typeof(IActivate))] public class MedicalScannerComponent : SharedMedicalScannerComponent, IActivate { - private AppearanceComponent _appearance; - private BoundUserInterface _userInterface; - private ContainerSlot _bodyContainer; + private ContainerSlot _bodyContainer = default!; private readonly Vector2 _ejectOffset = new Vector2(-0.5f, 0f); public bool IsOccupied => _bodyContainer.ContainedEntity != null; - private PowerReceiverComponent _powerReceiver; - private bool Powered => _powerReceiver.Powered; + [ViewVariables] + 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() { base.Initialize(); - _appearance = Owner.GetComponent(); - _userInterface = Owner.GetComponent() - .GetBoundUserInterface(MedicalScannerUiKey.Key); - _userInterface.OnReceiveMessage += OnUiReceiveMessage; - _bodyContainer = ContainerManagerComponent.Ensure($"{Name}-bodyContainer", Owner); - _powerReceiver = Owner.GetComponent(); + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += OnUiReceiveMessage; + } - //TODO: write this so that it checks for a change in power events and acts accordingly. + _bodyContainer = ContainerManagerComponent.Ensure($"{Name}-bodyContainer", Owner); + + // TODO: write this so that it checks for a change in power events and acts accordingly. var newState = GetUserInterfaceState(); - _userInterface.SetState(newState); + UserInterface?.SetState(newState); UpdateUserInterface(); } @@ -62,11 +69,15 @@ namespace Content.Server.GameObjects.Components.Medical var body = _bodyContainer.ContainedEntity; if (body == null) { - _appearance.SetData(MedicalScannerVisuals.Status, MedicalScannerStatus.Open); + if (Owner.TryGetComponent(out AppearanceComponent? appearance)) + { + appearance?.SetData(MedicalScannerVisuals.Status, MedicalScannerStatus.Open); + }; + return EmptyUIState; } - if (!body.TryGetComponent(out IDamageableComponent damageable) || + if (!body.TryGetComponent(out IDamageableComponent? damageable) || damageable.CurrentDamageState == DamageState.Dead) { return EmptyUIState; @@ -86,7 +97,7 @@ namespace Content.Server.GameObjects.Components.Medical } var newState = GetUserInterfaceState(); - _userInterface.SetState(newState); + UserInterface?.SetState(newState); } private MedicalScannerStatus GetStatusFromDamageState(DamageState damageState) @@ -115,12 +126,15 @@ namespace Content.Server.GameObjects.Components.Medical private void UpdateAppearance() { - _appearance.SetData(MedicalScannerVisuals.Status, GetStatus()); + if (Owner.TryGetComponent(out AppearanceComponent? appearance)) + { + appearance.SetData(MedicalScannerVisuals.Status, GetStatus()); + } } public void Activate(ActivateEventArgs args) { - if (!args.User.TryGetComponent(out IActorComponent actor)) + if (!args.User.TryGetComponent(out IActorComponent? actor)) { return; } @@ -128,7 +142,7 @@ namespace Content.Server.GameObjects.Components.Medical if (!Powered) return; - _userInterface.Open(actor.playerSession); + UserInterface?.Open(actor.playerSession); } [Verb] diff --git a/Content.Server/GameObjects/Components/Mining/AsteroidRockComponent.cs b/Content.Server/GameObjects/Components/Mining/AsteroidRockComponent.cs index 08a4bffd48..298b5858ec 100644 --- a/Content.Server/GameObjects/Components/Mining/AsteroidRockComponent.cs +++ b/Content.Server/GameObjects/Components/Mining/AsteroidRockComponent.cs @@ -27,7 +27,8 @@ namespace Content.Server.GameObjects.Components.Mining public override void Initialize() { base.Initialize(); - var spriteComponent = Owner.GetComponent(); + + var spriteComponent = Owner.EnsureComponent(); spriteComponent.LayerSetState(0, _random.Pick(SpriteStates)); } diff --git a/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs b/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs index ac635153e2..e613b33f50 100644 --- a/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs +++ b/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs @@ -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 Robust.Server.AI; using Robust.Shared.GameObjects; @@ -14,23 +15,23 @@ namespace Content.Server.GameObjects.Components.Movement [RegisterComponent, ComponentReference(typeof(IMoverComponent))] public class AiControllerComponent : Component, IMoverComponent { - private string _logicName; + private string? _logicName; private float _visionRadius; public override string Name => "AiController"; [ViewVariables(VVAccess.ReadWrite)] - public string LogicName + public string? LogicName { get => _logicName; set { _logicName = value; - Processor = null; + Processor = null!; } } - public AiLogicProcessor Processor { get; set; } + public AiLogicProcessor? Processor { get; set; } [ViewVariables(VVAccess.ReadWrite)] public float VisionRadius @@ -45,9 +46,8 @@ namespace Content.Server.GameObjects.Components.Movement base.Initialize(); // This component requires a collidable component. - if (!Owner.HasComponent()) - Owner.AddComponent(); - + Owner.EnsureComponent(); + EntitySystem.Get().ProcessorInitialize(this); } @@ -74,7 +74,7 @@ namespace Content.Server.GameObjects.Components.Movement { get { - if (Owner.TryGetComponent(out MovementSpeedModifierComponent component)) + if (Owner.TryGetComponent(out MovementSpeedModifierComponent? component)) { return component.CurrentWalkSpeed; } @@ -91,7 +91,7 @@ namespace Content.Server.GameObjects.Components.Movement { get { - if (Owner.TryGetComponent(out MovementSpeedModifierComponent component)) + if (Owner.TryGetComponent(out MovementSpeedModifierComponent? component)) { return component.CurrentSprintSpeed; } diff --git a/Content.Server/GameObjects/Components/Movement/ClimbableComponent.cs b/Content.Server/GameObjects/Components/Movement/ClimbableComponent.cs index a6bb5ed2fb..45baeb54e7 100644 --- a/Content.Server/GameObjects/Components/Movement/ClimbableComponent.cs +++ b/Content.Server/GameObjects/Components/Movement/ClimbableComponent.cs @@ -24,10 +24,8 @@ namespace Content.Server.GameObjects.Components.Movement [ComponentReference(typeof(IClimbable))] public class ClimbableComponent : SharedClimbableComponent, IDragDropOn { -#pragma warning disable 649 [Dependency] private readonly IServerNotifyManager _notifyManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; -#pragma warning restore 649 /// /// The range from which this entity can be climbed. @@ -81,7 +79,7 @@ namespace Content.Server.GameObjects.Components.Movement var bodyManager = eventArgs.User.GetComponent(); if (bodyManager.GetBodyPartsOfType(Shared.GameObjects.Components.Body.BodyPartType.Leg).Count == 0 || - bodyManager.GetBodyPartsOfType(Shared.GameObjects.Components.Body.BodyPartType.Foot).Count == 0) + bodyManager.GetBodyPartsOfType(Shared.GameObjects.Components.Body.BodyPartType.Foot).Count == 0) { _notifyManager.PopupMessage(eventArgs.User, eventArgs.User, Loc.GetString("You are unable to climb!")); @@ -102,10 +100,10 @@ namespace Content.Server.GameObjects.Components.Movement } else // user is dragging some other entity onto a climbable { - if (eventArgs.Target == null || !eventArgs.Dropped.HasComponent()) + if (eventArgs.Target == null || !eventArgs.Dropped.HasComponent()) { _notifyManager.PopupMessage(eventArgs.User, eventArgs.User, Loc.GetString("You can't do that!")); - + return false; } diff --git a/Content.Server/GameObjects/Components/Movement/ServerPortalComponent.cs b/Content.Server/GameObjects/Components/Movement/ServerPortalComponent.cs index 1c5abcdfe0..c80771c2de 100644 --- a/Content.Server/GameObjects/Components/Movement/ServerPortalComponent.cs +++ b/Content.Server/GameObjects/Components/Movement/ServerPortalComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Collections.Generic; using Content.Shared.GameObjects.Components.Movement; using Robust.Server.GameObjects; @@ -18,9 +19,7 @@ namespace Content.Server.GameObjects.Components.Movement [RegisterComponent] public class ServerPortalComponent : SharedPortalComponent { -#pragma warning disable 649 - [Dependency] private readonly IServerEntityManager _serverEntityManager; -#pragma warning restore 649 + [Dependency] private readonly IServerEntityManager _serverEntityManager = default!; // Potential improvements: Different sounds, // Add Gateways @@ -28,15 +27,14 @@ namespace Content.Server.GameObjects.Components.Movement // Put portal above most other things layer-wise // 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; [ViewVariables(VVAccess.ReadWrite)] private float _individualPortalCooldown; [ViewVariables] private float _overallPortalCooldown; [ViewVariables] private bool _onCooldown; - [ViewVariables] private string _departureSound; - [ViewVariables] private string _arrivalSound; - public List immuneEntities = new List(); // K + [ViewVariables] private string _departureSound = ""; + [ViewVariables] private string _arrivalSound = ""; + public readonly List ImmuneEntities = new List(); // K [ViewVariables(VVAccess.ReadWrite)] private float _aliveTime; 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"); } - public override void Initialize() - { - base.Initialize(); - _appearanceComponent = Owner.GetComponent(); - } - public override void OnAdd() { // 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() { if (_connectingTeleporter == null) @@ -108,23 +93,24 @@ namespace Content.Server.GameObjects.Components.Movement } _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 && _connectingTeleporter.TryGetComponent(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) { // TODO: Check if it's slotted etc. Otherwise the slot item itself gets ported. - if (!immuneEntities.Contains(entity) && entity.HasComponent()) + if (!ImmuneEntities.Contains(entity) && entity.HasComponent()) { return true; } @@ -192,7 +178,7 @@ namespace Content.Server.GameObjects.Components.Movement public void TryPortalEntity(IEntity entity) { - if (immuneEntities.Contains(entity) || _connectingTeleporter == null) + if (ImmuneEntities.Contains(entity) || _connectingTeleporter == null) { return; } @@ -208,9 +194,9 @@ namespace Content.Server.GameObjects.Components.Movement soundPlayer.PlayAtCoords(_arrivalSound, entity.Transform.GridPosition); TryChangeState(PortalState.RecentlyTeleported); // To stop spam teleporting. Could potentially look at adding a timer to flush this from the portal - immuneEntities.Add(entity); - _connectingTeleporter.GetComponent().immuneEntities.Add(entity); - Timer.Spawn(TimeSpan.FromSeconds(_individualPortalCooldown), () => releaseCooldown(entity)); + ImmuneEntities.Add(entity); + _connectingTeleporter.GetComponent().ImmuneEntities.Add(entity); + Timer.Spawn(TimeSpan.FromSeconds(_individualPortalCooldown), () => ReleaseCooldown(entity)); StartCooldown(); } } diff --git a/Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs b/Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs index e1e44cec21..f731f04646 100644 --- a/Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs +++ b/Content.Server/GameObjects/Components/Movement/ServerTeleporterComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Linq; using Content.Shared.GameObjects.Components.Movement; using Content.Shared.Interfaces.GameObjects.Components; @@ -24,11 +25,10 @@ namespace Content.Server.GameObjects.Components.Movement [RegisterComponent] public class ServerTeleporterComponent : Component, IAfterInteract { -#pragma warning disable 649 - [Dependency] private readonly IMapManager _mapManager; - [Dependency] private readonly IServerEntityManager _serverEntityManager; - [Dependency] private readonly IRobustRandom _spreadRandom; -#pragma warning restore 649 + [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly IServerEntityManager _serverEntityManager = default!; + [Dependency] private readonly IRobustRandom _spreadRandom = default!; + // TODO: Look at MapManager.Map for Beacons to get all entities on grid public ItemTeleporterState State => _state; @@ -39,15 +39,13 @@ namespace Content.Server.GameObjects.Components.Movement [ViewVariables] private int _range; [ViewVariables] private ItemTeleporterState _state; [ViewVariables] private TeleporterType _teleporterType; - [ViewVariables] private string _departureSound; - [ViewVariables] private string _arrivalSound; - [ViewVariables] private string _cooldownSound; + [ViewVariables] private string _departureSound = ""; + [ViewVariables] private string _arrivalSound = ""; + [ViewVariables] private string? _cooldownSound; // If the direct OR random teleport will try to avoid hitting collidables [ViewVariables] private bool _avoidCollidable; [ViewVariables] private float _portalAliveTime; - private AppearanceComponent _appearanceComponent; - public override void ExposeData(ObjectSerializer 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? } - public override void OnRemove() - { - _appearanceComponent = null; - - base.OnRemove(); - } - private void SetState(ItemTeleporterState newState) { + if (!Owner.TryGetComponent(out AppearanceComponent? appearance)) + { + return; + } + if (newState == ItemTeleporterState.Cooldown) { - _appearanceComponent.SetData(TeleporterVisuals.VisualState, TeleporterVisualState.Charging); + appearance.SetData(TeleporterVisuals.VisualState, TeleporterVisualState.Charging); } else { - _appearanceComponent.SetData(TeleporterVisuals.VisualState, TeleporterVisualState.Ready); + appearance.SetData(TeleporterVisuals.VisualState, TeleporterVisualState.Ready); } _state = newState; } @@ -149,12 +145,11 @@ namespace Content.Server.GameObjects.Components.Movement public override void Initialize() { - _appearanceComponent = Owner.GetComponent(); - _state = ItemTeleporterState.Off; 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. foreach (var entity in _serverEntityManager.GetEntitiesIntersecting(user.Transform.MapID, target)) @@ -167,7 +162,7 @@ namespace Content.Server.GameObjects.Components.Movement return true; } - private Vector2 randomEmptySpot(IEntity user, int range) + private Vector2 RandomEmptySpot(IEntity user, int range) { Vector2 targetVector = user.Transform.GridPosition.Position; // Definitely a better way to do this @@ -176,7 +171,7 @@ namespace Content.Server.GameObjects.Components.Movement var randomRange = _spreadRandom.Next(0, range); var angle = Angle.FromDegrees(_spreadRandom.Next(0, 359)); targetVector = user.Transform.GridPosition.Position + angle.ToVec() * randomRange; - if (emptySpace(user, targetVector)) + if (EmptySpace(user, targetVector)) { return targetVector; } @@ -200,7 +195,7 @@ namespace Content.Server.GameObjects.Components.Movement Vector2 targetVector; if (_avoidCollidable) { - targetVector = randomEmptySpot(user, _range); + targetVector = RandomEmptySpot(user, _range); } else { @@ -227,7 +222,7 @@ namespace Content.Server.GameObjects.Components.Movement public void Teleport(IEntity user, Vector2 vector) { // Messy maybe? - GridCoordinates targetGrid = new GridCoordinates(vector, user.Transform.GridID); + var targetGrid = new GridCoordinates(vector, user.Transform.GridID); var soundPlayer = EntitySystem.Get(); // If portals use those, otherwise just move em over @@ -240,10 +235,11 @@ namespace Content.Server.GameObjects.Components.Movement // Arrival portal var arrivalPortal = _serverEntityManager.SpawnEntity("Portal", targetGrid); - arrivalPortal.TryGetComponent(out var arrivalComponent); - - // Connect. TODO: If the OnUpdate in ServerPortalComponent is changed this may need to change as well. - arrivalComponent.TryConnectPortal(departurePortal); + if (arrivalPortal.TryGetComponent(out var arrivalComponent)) + { + // Connect. TODO: If the OnUpdate in ServerPortalComponent is changed this may need to change as well. + arrivalComponent.TryConnectPortal(departurePortal); + } } else { diff --git a/Content.Server/GameObjects/Components/Movement/ShuttleControllerComponent.cs b/Content.Server/GameObjects/Components/Movement/ShuttleControllerComponent.cs index 1b39598c2f..e0b7f49f66 100644 --- a/Content.Server/GameObjects/Components/Movement/ShuttleControllerComponent.cs +++ b/Content.Server/GameObjects/Components/Movement/ShuttleControllerComponent.cs @@ -22,10 +22,8 @@ namespace Content.Server.GameObjects.Components.Movement [ComponentReference(typeof(IMoverComponent))] internal class ShuttleControllerComponent : Component, IMoverComponent { -#pragma warning disable 649 [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; -#pragma warning restore 649 private bool _movingUp; private bool _movingDown; diff --git a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/ApcNetNodeGroup.cs b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/ApcNetNodeGroup.cs index ff80b1a74f..8e1d103c15 100644 --- a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/ApcNetNodeGroup.cs +++ b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/ApcNetNodeGroup.cs @@ -48,7 +48,12 @@ namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups 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) diff --git a/Content.Server/GameObjects/Components/Nutrition/FoodComponent.cs b/Content.Server/GameObjects/Components/Nutrition/FoodComponent.cs index e4440aefa9..cec956d208 100644 --- a/Content.Server/GameObjects/Components/Nutrition/FoodComponent.cs +++ b/Content.Server/GameObjects/Components/Nutrition/FoodComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Collections.Generic; using Content.Server.GameObjects.Components.Body.Digestive; using Content.Server.GameObjects.Components.Chemistry; @@ -25,24 +26,30 @@ namespace Content.Server.GameObjects.Components.Nutrition [ComponentReference(typeof(IAfterInteract))] public class FoodComponent : Component, IUse, IAfterInteract { -#pragma warning disable 649 - [Dependency] private readonly IEntitySystemManager _entitySystem; -#pragma warning restore 649 + [Dependency] private readonly IEntitySystemManager _entitySystem = default!; + public override string Name => "Food"; - [ViewVariables] - private string _useSound; - [ViewVariables] - private string _trashPrototype; - [ViewVariables] - private SolutionComponent _contents; - [ViewVariables] - private ReagentUnit _transferAmount; + [ViewVariables] private string _useSound = ""; + [ViewVariables] private string? _trashPrototype; + [ViewVariables] private ReagentUnit _transferAmount; private UtensilType _utensilsNeeded; - public int UsesRemaining => _contents.CurrentVolume == 0 - ? - 0 : Math.Max(1, (int)Math.Ceiling((_contents.CurrentVolume / _transferAmount).Float())); + [ViewVariables] + public int UsesRemaining + { + 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) { @@ -60,7 +67,7 @@ namespace Content.Server.GameObjects.Components.Nutrition { var types = new List(); - foreach (UtensilType type in Enum.GetValues(typeof(UtensilType))) + foreach (var type in (UtensilType[]) Enum.GetValues(typeof(UtensilType))) { if ((_utensilsNeeded & type) != 0) { @@ -75,8 +82,7 @@ namespace Content.Server.GameObjects.Components.Nutrition public override void Initialize() { base.Initialize(); - _contents = Owner.GetComponent(); - + Owner.EnsureComponent(); } bool IUse.UseEntity(UseEntityEventArgs eventArgs) @@ -101,8 +107,13 @@ namespace Content.Server.GameObjects.Components.Nutrition 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) { return false; @@ -116,7 +127,7 @@ namespace Content.Server.GameObjects.Components.Nutrition var trueTarget = target ?? user; - if (!trueTarget.TryGetComponent(out StomachComponent stomach)) + if (!trueTarget.TryGetComponent(out StomachComponent? stomach)) { return false; } @@ -130,11 +141,11 @@ namespace Content.Server.GameObjects.Components.Nutrition utensils = new List(); var types = UtensilType.None; - if (user.TryGetComponent(out HandsComponent hands)) + if (user.TryGetComponent(out HandsComponent? hands)) { foreach (var item in hands.GetAllHeldItems()) { - if (!item.Owner.TryGetComponent(out UtensilComponent utensil)) + if (!item.Owner.TryGetComponent(out UtensilComponent? utensil)) { continue; } @@ -156,11 +167,11 @@ namespace Content.Server.GameObjects.Components.Nutrition return false; } - var transferAmount = ReagentUnit.Min(_transferAmount, _contents.CurrentVolume); - var split = _contents.SplitSolution(transferAmount); + var transferAmount = ReagentUnit.Min(_transferAmount, solution.CurrentVolume); + var split = solution.SplitSolution(transferAmount); if (!stomach.TryTransferSolution(split)) { - _contents.TryAddSolution(split); + solution.TryAddSolution(split); trueTarget.PopupMessage(user, Loc.GetString("You can't eat any more!")); return false; } @@ -194,13 +205,13 @@ namespace Content.Server.GameObjects.Components.Nutrition var finisher = Owner.EntityManager.SpawnEntity(_trashPrototype, position); // If the user is holding the item - if (user.TryGetComponent(out HandsComponent handsComponent) && + if (user.TryGetComponent(out HandsComponent? handsComponent) && handsComponent.IsHolding(Owner)) { Owner.Delete(); // Put the trash in the user's hand - if (finisher.TryGetComponent(out ItemComponent item) && + if (finisher.TryGetComponent(out ItemComponent? item) && handsComponent.CanPutInHand(item)) { handsComponent.PutInHand(item); diff --git a/Content.Server/GameObjects/Components/PDA/PDAComponent.cs b/Content.Server/GameObjects/Components/PDA/PDAComponent.cs index 1aa9f2f776..e3e4f810cf 100644 --- a/Content.Server/GameObjects/Components/PDA/PDAComponent.cs +++ b/Content.Server/GameObjects/Components/PDA/PDAComponent.cs @@ -37,21 +37,24 @@ namespace Content.Server.GameObjects.Components.PDA [Dependency] private readonly IEntityManager _entityManager = default!; [ViewVariables] private Container _idSlot = default!; - [ViewVariables] private PointLightComponent _pdaLight = default!; [ViewVariables] private bool _lightOn; - [ViewVariables] private BoundUserInterface _interface = default!; [ViewVariables] private string _startingIdCard = default!; [ViewVariables] public bool IdSlotEmpty => _idSlot.ContainedEntities.Count < 1; [ViewVariables] public string? OwnerName { get; private set; } [ViewVariables] public IdCardComponent? ContainedID { get; private set; } - [ViewVariables] private AppearanceComponent _appearance = default!; - [ViewVariables] private UplinkAccount? _syndicateUplinkAccount; [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() { _accessSet = new PdaAccessSet(this); @@ -67,11 +70,12 @@ namespace Content.Server.GameObjects.Components.PDA { base.Initialize(); _idSlot = ContainerManagerComponent.Ensure("pda_entity_container", Owner, out var existed); - _pdaLight = Owner.GetComponent(); - _appearance = Owner.GetComponent(); - _interface = Owner.GetComponent() - .GetBoundUserInterface(PDAUiKey.Key); - _interface.OnReceiveMessage += UserInterfaceOnReceiveMessage; + + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; + } + var idCard = _entityManager.SpawnEntity(_startingIdCard, Owner.Transform.GridPosition); var idCardComponent = idCard.GetComponent(); _idSlot.Insert(idCardComponent.Owner); @@ -129,11 +133,11 @@ namespace Content.Server.GameObjects.Components.PDA var accData = new UplinkAccountData(_syndicateUplinkAccount.AccountHolder, _syndicateUplinkAccount.Balance); var listings = _uplinkManager.FetchListings.ToArray(); - _interface.SetState(new PDAUpdateState(_lightOn, ownerInfo, accData, listings)); + UserInterface?.SetState(new PDAUpdateState(_lightOn, ownerInfo, accData, listings)); } else { - _interface.SetState(new PDAUpdateState(_lightOn, ownerInfo)); + UserInterface?.SetState(new PDAUpdateState(_lightOn, ownerInfo)); } UpdatePDAAppearance(); @@ -141,7 +145,10 @@ namespace Content.Server.GameObjects.Components.PDA private void UpdatePDAAppearance() { - _appearance?.SetData(PDAVisuals.FlashlightLit, _lightOn); + if (Owner.TryGetComponent(out AppearanceComponent? appearance)) + { + appearance.SetData(PDAVisuals.FlashlightLit, _lightOn); + } } public async Task InteractUsing(InteractUsingEventArgs eventArgs) @@ -169,7 +176,7 @@ namespace Content.Server.GameObjects.Components.PDA return; } - _interface.Open(actor.playerSession); + UserInterface?.Open(actor.playerSession); UpdatePDAAppearance(); } @@ -180,7 +187,7 @@ namespace Content.Server.GameObjects.Components.PDA return false; } - _interface.Open(actor.playerSession); + UserInterface?.Open(actor.playerSession); UpdatePDAAppearance(); return true; } @@ -217,8 +224,13 @@ namespace Content.Server.GameObjects.Components.PDA private void ToggleLight() { + if (!Owner.TryGetComponent(out PointLightComponent? light)) + { + return; + } + _lightOn = !_lightOn; - _pdaLight.Enabled = _lightOn; + light.Enabled = _lightOn; EntitySystem.Get().PlayFromEntity("/Audio/Items/flashlight_toggle.ogg", Owner); UpdatePDAUserInterface(); } diff --git a/Content.Server/GameObjects/Components/Paper/PaperComponent.cs b/Content.Server/GameObjects/Components/Paper/PaperComponent.cs index 54193918d9..b3b9a8a459 100644 --- a/Content.Server/GameObjects/Components/Paper/PaperComponent.cs +++ b/Content.Server/GameObjects/Components/Paper/PaperComponent.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +#nullable enable +using System.Threading.Tasks; using Content.Shared.GameObjects.Components; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces.GameObjects.Components; @@ -13,24 +14,30 @@ namespace Content.Server.GameObjects.Components.Paper [RegisterComponent] public class PaperComponent : SharedPaperComponent, IExamine, IInteractUsing, IUse { - - private BoundUserInterface _userInterface; - private string _content; + private string _content = ""; private PaperAction _mode; + private BoundUserInterface? UserInterface => + Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) && + ui.TryGetBoundUserInterface(PaperUiKey.Key, out var boundUi) + ? boundUi + : null; + public override void Initialize() { base.Initialize(); - _userInterface = Owner.GetComponent() - .GetBoundUserInterface(PaperUiKey.Key); - _userInterface.OnReceiveMessage += OnUiReceiveMessage; - _content = ""; + + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += OnUiReceiveMessage; + } + _mode = PaperAction.Read; UpdateUserInterface(); } private void UpdateUserInterface() { - _userInterface.SetState(new PaperBoundUserInterfaceState(_content, _mode)); + UserInterface?.SetState(new PaperBoundUserInterfaceState(_content, _mode)); } public void Examine(FormattedMessage message, bool inDetailsRange) @@ -43,11 +50,12 @@ namespace Content.Server.GameObjects.Components.Paper public bool UseEntity(UseEntityEventArgs eventArgs) { - if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) + if (!eventArgs.User.TryGetComponent(out IActorComponent? actor)) return false; + _mode = PaperAction.Read; UpdateUserInterface(); - _userInterface.Open(actor.playerSession); + UserInterface?.Open(actor.playerSession); return true; } @@ -59,7 +67,7 @@ namespace Content.Server.GameObjects.Components.Paper _content += msg.Text + '\n'; - if (Owner.TryGetComponent(out SpriteComponent sprite)) + if (Owner.TryGetComponent(out SpriteComponent? sprite)) { sprite.LayerSetState(1, "paper_words"); } @@ -71,12 +79,12 @@ namespace Content.Server.GameObjects.Components.Paper { if (!eventArgs.Using.HasComponent()) return false; - if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) + if (!eventArgs.User.TryGetComponent(out IActorComponent? actor)) return false; _mode = PaperAction.Write; UpdateUserInterface(); - _userInterface.Open(actor.playerSession); + UserInterface?.Open(actor.playerSession); return true; } } diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/ApcComponent.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/ApcComponent.cs index f55ded352a..7643db7112 100644 --- a/Content.Server/GameObjects/Components/Power/ApcNetComponents/ApcComponent.cs +++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/ApcComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; using Content.Server.GameObjects.Components.Power.PowerNetComponents; using Content.Shared.GameObjects.Components.Power; @@ -20,17 +21,12 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents [ComponentReference(typeof(IActivate))] public class ApcComponent : BaseApcNetComponent, IActivate { + [Dependency] private readonly IGameTiming _gameTiming = default!; + public override string Name => "Apc"; - [ViewVariables] - public BatteryComponent Battery { get; private set; } - public bool MainBreakerEnabled { get; private set; } = true; - private BoundUserInterface _userInterface; - - private AppearanceComponent _appearance; - private ApcChargeState _lastChargeState; private TimeSpan _lastChargeStateChange; @@ -39,7 +35,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents private TimeSpan _lastExternalPowerStateChange; - private float _lastCharge = 0f; + private float _lastCharge; private TimeSpan _lastChargeChange; @@ -49,17 +45,27 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents private const int VisualsChangeDelay = 1; -#pragma warning disable 649 - [Dependency] private readonly IGameTiming _gameTiming; -#pragma warning restore 649 + [ViewVariables] + private BoundUserInterface? UserInterface => + 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() { base.Initialize(); - Battery = Owner.GetComponent(); - _appearance = Owner.GetComponent(); - _userInterface = Owner.GetComponent().GetBoundUserInterface(ApcUiKey.Key); - _userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; + + Owner.EnsureComponent(); + Owner.EnsureComponent(); + + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; + } + Update(); } @@ -90,15 +96,23 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents { _lastChargeState = newState; _lastChargeStateChange = _gameTiming.CurTime; - _appearance.SetData(ApcVisuals.ChargeState, newState); + + if (Owner.TryGetComponent(out AppearanceComponent? appearance)) + { + appearance.SetData(ApcVisuals.ChargeState, newState); + } } - var newCharge = Battery.CurrentCharge; - if (newCharge != _lastCharge && _lastChargeChange + TimeSpan.FromSeconds(VisualsChangeDelay) < _gameTiming.CurTime) + + Owner.TryGetComponent(out BatteryComponent? battery); + + var newCharge = battery?.CurrentCharge; + if (newCharge != null && newCharge != _lastCharge && _lastChargeChange + TimeSpan.FromSeconds(VisualsChangeDelay) < _gameTiming.CurTime) { - _lastCharge = newCharge; + _lastCharge = newCharge.Value; _lastChargeChange = _gameTiming.CurTime; _uiDirty = true; } + var extPowerState = CalcExtPowerState(); if (extPowerState != _lastExternalPowerState && _lastExternalPowerStateChange + TimeSpan.FromSeconds(VisualsChangeDelay) < _gameTiming.CurTime) { @@ -106,21 +120,33 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents _lastExternalPowerStateChange = _gameTiming.CurTime; _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; } } 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) { return ApcChargeState.Full; } - var consumer = Owner.GetComponent(); + + if (!Owner.TryGetComponent(out PowerConsumerComponent? consumer)) + { + return ApcChargeState.Full; + } + if (consumer.DrawRate == consumer.ReceivedPower) { return ApcChargeState.Charging; @@ -133,7 +159,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents private ApcExternalPowerState CalcExtPowerState() { - if (!Owner.TryGetComponent(out BatteryStorageComponent batteryStorage)) + if (!Owner.TryGetComponent(out BatteryStorageComponent? batteryStorage)) { return ApcExternalPowerState.None; } @@ -154,11 +180,12 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents void IActivate.Activate(ActivateEventArgs eventArgs) { - if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) + if (!eventArgs.User.TryGetComponent(out IActorComponent? actor)) { return; } - _userInterface.Open(actor.playerSession); + + UserInterface?.Open(actor.playerSession); } } } diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/BaseCharger.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/BaseCharger.cs index 674a33dd1f..4b78446d42 100644 --- a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/BaseCharger.cs +++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/BaseCharger.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Threading.Tasks; using Content.Server.GameObjects.Components.GUI; 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 { [ViewVariables] - private BatteryComponent _heldBattery; + private BatteryComponent? _heldBattery; [ViewVariables] - private ContainerSlot _container; - - [ViewVariables] - private PowerReceiverComponent _powerReceiver; + private ContainerSlot _container = default!; [ViewVariables] private CellChargerStatus _status; - private AppearanceComponent _appearanceComponent; - [ViewVariables] private int _chargeRate; @@ -53,16 +49,25 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece public override void Initialize() { base.Initialize(); - _powerReceiver = Owner.GetComponent(); + + Owner.EnsureComponent(); _container = ContainerManagerComponent.Ensure($"{Name}-powerCellContainer", Owner); - _appearanceComponent = Owner.GetComponent(); // 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() { - _powerReceiver.OnPowerStateChanged -= PowerUpdate; + if (Owner.TryGetComponent(out PowerReceiverComponent? receiver)) + { + receiver.OnPowerStateChanged -= PowerUpdate; + } + + _heldBattery = null; + base.OnRemove(); } @@ -97,12 +102,12 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece _container.Remove(heldItem); _heldBattery = null; - if (user.TryGetComponent(out HandsComponent handsComponent)) + if (user.TryGetComponent(out HandsComponent? handsComponent)) { handsComponent.PutInHandOrDrop(heldItem.GetComponent()); } - if (heldItem.TryGetComponent(out ServerBatteryBarrelComponent batteryBarrelComponent)) + if (heldItem.TryGetComponent(out ServerBatteryBarrelComponent? batteryBarrelComponent)) { batteryBarrelComponent.UpdateAppearance(); } @@ -110,7 +115,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece UpdateStatus(); } - private void PowerUpdate(object sender, PowerStateEventArgs eventArgs) + private void PowerUpdate(object? sender, PowerStateEventArgs eventArgs) { UpdateStatus(); } @@ -125,7 +130,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece data.Visibility = VerbVisibility.Invisible; return; } - if (!user.TryGetComponent(out HandsComponent handsComponent)) + if (!user.TryGetComponent(out HandsComponent? handsComponent)) { data.Visibility = VerbVisibility.Invisible; return; @@ -143,7 +148,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece protected override void Activate(IEntity user, BaseCharger component) { - if (!user.TryGetComponent(out HandsComponent handsComponent)) + if (!user.TryGetComponent(out HandsComponent? handsComponent)) { return; } @@ -186,7 +191,8 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece private CellChargerStatus GetStatus() { - if (!_powerReceiver.Powered) + if (Owner.TryGetComponent(out PowerReceiverComponent? receiver) && + !receiver.Powered) { 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 var status = GetStatus(); - if (_status == status) + if (_status == status || + !Owner.TryGetComponent(out PowerReceiverComponent? receiver)) { return; } + _status = status; + Owner.TryGetComponent(out AppearanceComponent? appearance); + switch (_status) { // Update load just in case case CellChargerStatus.Off: - _powerReceiver.Load = 0; - _appearanceComponent?.SetData(CellVisual.Light, CellChargerStatus.Off); + receiver.Load = 0; + appearance?.SetData(CellVisual.Light, CellChargerStatus.Off); break; case CellChargerStatus.Empty: - _powerReceiver.Load = 0; - _appearanceComponent?.SetData(CellVisual.Light, CellChargerStatus.Empty); ; + receiver.Load = 0; + appearance?.SetData(CellVisual.Light, CellChargerStatus.Empty); break; case CellChargerStatus.Charging: - _powerReceiver.Load = (int) (_chargeRate / _transferEfficiency); - _appearanceComponent?.SetData(CellVisual.Light, CellChargerStatus.Charging); + receiver.Load = (int) (_chargeRate / _transferEfficiency); + appearance?.SetData(CellVisual.Light, CellChargerStatus.Charging); break; case CellChargerStatus.Charged: - _powerReceiver.Load = 0; - _appearanceComponent?.SetData(CellVisual.Light, CellChargerStatus.Charged); + receiver.Load = 0; + appearance?.SetData(CellVisual.Light, CellChargerStatus.Charged); break; default: 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 @@ -268,10 +279,17 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece private void TransferPower(float frameTime) { - if (!_powerReceiver.Powered) + if (Owner.TryGetComponent(out PowerReceiverComponent? receiver) && + !receiver.Powered) { return; } + + if (_heldBattery == null) + { + return; + } + _heldBattery.CurrentCharge += _chargeRate * frameTime; // Just so the sprite won't be set to 99.99999% visibility if (_heldBattery.MaxCharge - _heldBattery.CurrentCharge < 0.01) diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/LightBulbComponent.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/LightBulbComponent.cs index b33be166af..461698422d 100644 --- a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/LightBulbComponent.cs +++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/LightBulbComponent.cs @@ -108,7 +108,11 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece public void UpdateColor() { - var sprite = Owner.GetComponent(); + if (!Owner.TryGetComponent(out SpriteComponent sprite)) + { + return; + } + sprite.Color = Color; } diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PoweredLightComponent.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PoweredLightComponent.cs index 716e72ee7a..71befe71bc 100644 --- a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PoweredLightComponent.cs +++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PoweredLightComponent.cs @@ -225,14 +225,18 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece { base.Initialize(); - Owner.GetComponent().OnPowerStateChanged += UpdateLight; + Owner.EnsureComponent().OnPowerStateChanged += UpdateLight; _lightBulbContainer = ContainerManagerComponent.Ensure("light_bulb", Owner); } public override void OnRemove() { - Owner.GetComponent().OnPowerStateChanged -= UpdateLight; + if (Owner.TryGetComponent(out PowerReceiverComponent receiver)) + { + receiver.OnPowerStateChanged -= UpdateLight; + } + base.OnRemove(); } diff --git a/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs b/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs index ca14c4aa44..4165b82fbe 100644 --- a/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs @@ -13,12 +13,9 @@ namespace Content.Server.GameObjects.Components.Power { public override string Name => "PowerCell"; - private AppearanceComponent _appearance; - public override void Initialize() { base.Initialize(); - _appearance = Owner.GetComponent(); CurrentCharge = MaxCharge; UpdateVisuals(); } @@ -31,7 +28,10 @@ namespace Content.Server.GameObjects.Components.Power private void UpdateVisuals() { - _appearance?.SetData(PowerCellVisuals.ChargeLevel, CurrentCharge / MaxCharge); + if (Owner.TryGetComponent(out AppearanceComponent appearance)) + { + appearance.SetData(PowerCellVisuals.ChargeLevel, CurrentCharge / MaxCharge); + } } } } diff --git a/Content.Server/GameObjects/Components/Power/PowerNetComponents/BatteryDischargerComponent.cs b/Content.Server/GameObjects/Components/Power/PowerNetComponents/BatteryDischargerComponent.cs index af543ae52d..65eaafb285 100644 --- a/Content.Server/GameObjects/Components/Power/PowerNetComponents/BatteryDischargerComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerNetComponents/BatteryDischargerComponent.cs @@ -31,8 +31,9 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents public override void Initialize() { base.Initialize(); - _battery = Owner.GetComponent(); - _supplier = Owner.GetComponent(); + + _battery = Owner.EnsureComponent(); + _supplier = Owner.EnsureComponent(); UpdateSupplyRate(); } diff --git a/Content.Server/GameObjects/Components/Power/PowerNetComponents/BatteryStorageComponent.cs b/Content.Server/GameObjects/Components/Power/PowerNetComponents/BatteryStorageComponent.cs index d94452a977..416ac17a5c 100644 --- a/Content.Server/GameObjects/Components/Power/PowerNetComponents/BatteryStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerNetComponents/BatteryStorageComponent.cs @@ -31,8 +31,9 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents public override void Initialize() { base.Initialize(); - _battery = Owner.GetComponent(); - Consumer = Owner.GetComponent(); + + _battery = Owner.EnsureComponent(); + Consumer = Owner.EnsureComponent(); UpdateDrawRate(); } diff --git a/Content.Server/GameObjects/Components/Power/PowerNetComponents/SmesComponent.cs b/Content.Server/GameObjects/Components/Power/PowerNetComponents/SmesComponent.cs index 666befcf28..3cacb3ad86 100644 --- a/Content.Server/GameObjects/Components/Power/PowerNetComponents/SmesComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerNetComponents/SmesComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using Content.Shared.GameObjects.Components.Power; using Content.Shared.Utility; using Robust.Server.GameObjects; @@ -16,13 +17,11 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents [RegisterComponent] public class SmesComponent : Component { + [Dependency] private readonly IGameTiming _gameTiming = default!; + public override string Name => "Smes"; - private BatteryComponent _battery; - - private AppearanceComponent _appearance; - - private int _lastChargeLevel = 0; + private int _lastChargeLevel; private TimeSpan _lastChargeLevelChange; @@ -32,15 +31,12 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents private const int VisualsChangeDelay = 1; -#pragma warning disable 649 - [Dependency] private readonly IGameTiming _gameTiming; -#pragma warning restore 649 - public override void Initialize() { base.Initialize(); - _battery = Owner.GetComponent(); - _appearance = Owner.GetComponent(); + + Owner.EnsureComponent(); + Owner.EnsureComponent(); } public void OnUpdate() @@ -50,7 +46,11 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents { _lastChargeLevel = newLevel; _lastChargeLevelChange = _gameTiming.CurTime; - _appearance.SetData(SmesVisuals.LastChargeLevel, newLevel); + + if (Owner.TryGetComponent(out AppearanceComponent? appearance)) + { + appearance.SetData(SmesVisuals.LastChargeLevel, newLevel); + } } var newChargeState = GetNewChargeState(); @@ -58,13 +58,22 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents { _lastChargeState = newChargeState; _lastChargeStateChange = _gameTiming.CurTime; - _appearance.SetData(SmesVisuals.LastChargeState, newChargeState); + + if (Owner.TryGetComponent(out AppearanceComponent? appearance)) + { + appearance.SetData(SmesVisuals.LastChargeState, newChargeState); + } } } 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() diff --git a/Content.Server/GameObjects/Components/Power/PowerNetComponents/SolarControlConsoleComponent.cs b/Content.Server/GameObjects/Components/Power/PowerNetComponents/SolarControlConsoleComponent.cs index 6c6d63203c..1670cb23dc 100644 --- a/Content.Server/GameObjects/Components/Power/PowerNetComponents/SolarControlConsoleComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerNetComponents/SolarControlConsoleComponent.cs @@ -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.Shared.GameObjects.Components.Power; using Content.Shared.Interfaces.GameObjects.Components; @@ -7,6 +8,7 @@ using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; +using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Power.PowerNetComponents { @@ -14,28 +16,34 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents [ComponentReference(typeof(IActivate))] public class SolarControlConsoleComponent : SharedSolarControlConsoleComponent, IActivate { -#pragma warning disable 649 - [Dependency] private IEntitySystemManager _entitySystemManager; -#pragma warning restore 649 + [Dependency] private readonly IEntitySystemManager _entitySystemManager = default!; - private BoundUserInterface _userInterface; - private PowerReceiverComponent _powerReceiver; - private PowerSolarSystem _powerSolarSystem; - private bool Powered => _powerReceiver.Powered; + private PowerSolarSystem _powerSolarSystem = default!; + private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered; + + [ViewVariables] + private BoundUserInterface? UserInterface => + Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) && + ui.TryGetBoundUserInterface(SolarControlConsoleUiKey.Key, out var boundUi) + ? boundUi + : null; public override void Initialize() { base.Initialize(); - _userInterface = Owner.GetComponent().GetBoundUserInterface(SolarControlConsoleUiKey.Key); - _userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; - _powerReceiver = Owner.GetComponent(); + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; + } + + Owner.EnsureComponent(); _powerSolarSystem = _entitySystemManager.GetEntitySystem(); } 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) @@ -57,7 +65,7 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents void IActivate.Activate(ActivateEventArgs eventArgs) { - if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) + if (!eventArgs.User.TryGetComponent(out IActorComponent? actor)) { return; } @@ -69,7 +77,7 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents // always update the UI immediately before opening, just in case UpdateUIState(); - _userInterface.Open(actor.playerSession); + UserInterface?.Open(actor.playerSession); } } } diff --git a/Content.Server/GameObjects/Components/Projectiles/ExplosiveProjectileComponent.cs b/Content.Server/GameObjects/Components/Projectiles/ExplosiveProjectileComponent.cs index 231e4ab707..2252ad1ea2 100644 --- a/Content.Server/GameObjects/Components/Projectiles/ExplosiveProjectileComponent.cs +++ b/Content.Server/GameObjects/Components/Projectiles/ExplosiveProjectileComponent.cs @@ -15,17 +15,16 @@ namespace Content.Server.GameObjects.Components.Projectiles public override void Initialize() { base.Initialize(); - if (!Owner.HasComponent()) - { - Logger.Error("ExplosiveProjectiles need an ExplosiveComponent"); - throw new InvalidOperationException(); - } + + Owner.EnsureComponent(); } void ICollideBehavior.CollideWith(IEntity entity) { - var explosiveComponent = Owner.GetComponent(); - explosiveComponent.Explosion(); + if (Owner.TryGetComponent(out ExplosiveComponent explosive)) + { + explosive.Explosion(); + } } // Projectile should handle the deleting @@ -34,4 +33,4 @@ namespace Content.Server.GameObjects.Components.Projectiles return; } } -} \ No newline at end of file +} diff --git a/Content.Server/GameObjects/Components/Projectiles/FlashProjectileComponent.cs b/Content.Server/GameObjects/Components/Projectiles/FlashProjectileComponent.cs index d4e8dab9eb..3a9c2f9a4f 100644 --- a/Content.Server/GameObjects/Components/Projectiles/FlashProjectileComponent.cs +++ b/Content.Server/GameObjects/Components/Projectiles/FlashProjectileComponent.cs @@ -31,10 +31,7 @@ namespace Content.Server.GameObjects.Components.Projectiles { base.Initialize(); // Shouldn't be using this without a ProjectileComponent because it will just immediately collide with thrower - if (!Owner.HasComponent()) - { - throw new InvalidOperationException(); - } + Owner.EnsureComponent(); } void ICollideBehavior.CollideWith(IEntity entity) diff --git a/Content.Server/GameObjects/Components/RadioComponent.cs b/Content.Server/GameObjects/Components/RadioComponent.cs index daef1622b0..c2df969c05 100644 --- a/Content.Server/GameObjects/Components/RadioComponent.cs +++ b/Content.Server/GameObjects/Components/RadioComponent.cs @@ -12,10 +12,8 @@ namespace Content.Server.GameObjects.Components [RegisterComponent] class RadioComponent : Component, IUse, IListen { -#pragma warning disable 649 [Dependency] private readonly IEntitySystemManager _entitySystemManager = default!; [Dependency] private readonly IServerNotifyManager _notifyManager = default!; -#pragma warning restore 649 public override string Name => "Radio"; diff --git a/Content.Server/GameObjects/Components/Recycling/RecyclerComponent.cs b/Content.Server/GameObjects/Components/Recycling/RecyclerComponent.cs index 124911e98d..93229746f5 100644 --- a/Content.Server/GameObjects/Components/Recycling/RecyclerComponent.cs +++ b/Content.Server/GameObjects/Components/Recycling/RecyclerComponent.cs @@ -28,9 +28,7 @@ namespace Content.Server.GameObjects.Components.Recycling [RegisterComponent] public class RecyclerComponent : Component, ICollideBehavior { -#pragma warning disable 649 [Dependency] private readonly IEntityManager _entityManager = default!; -#pragma warning restore 649 public override string Name => "Recycler"; diff --git a/Content.Server/GameObjects/Components/Research/LatheComponent.cs b/Content.Server/GameObjects/Components/Research/LatheComponent.cs index 55b2ddbbcb..f9e434929f 100644 --- a/Content.Server/GameObjects/Components/Research/LatheComponent.cs +++ b/Content.Server/GameObjects/Components/Research/LatheComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -25,15 +26,12 @@ namespace Content.Server.GameObjects.Components.Research { public const int VolumePerSheet = 3750; - private BoundUserInterface _userInterface; - [ViewVariables] public Queue Queue { get; } = new Queue(); [ViewVariables] - public bool Producing { get; private set; } = false; + public bool Producing { get; private set; } - private AppearanceComponent _appearance; private LatheState _state = LatheState.Base; protected virtual LatheState State @@ -42,19 +40,26 @@ namespace Content.Server.GameObjects.Components.Research set => _state = value; } - private LatheRecipePrototype _producingRecipe = null; - private PowerReceiverComponent _powerReceiver; - private bool Powered => _powerReceiver.Powered; + private LatheRecipePrototype? _producingRecipe; + private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered; 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() { base.Initialize(); - _userInterface = Owner.GetComponent().GetBoundUserInterface(LatheUiKey.Key); - _userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; - _powerReceiver = Owner.GetComponent(); - _appearance = Owner.GetComponent(); + + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; + } } private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage message) @@ -66,28 +71,28 @@ namespace Content.Server.GameObjects.Components.Research { case LatheQueueRecipeMessage msg: _prototypeManager.TryIndex(msg.ID, out LatheRecipePrototype recipe); - if (recipe != null) + if (recipe != null!) for (var i = 0; i < msg.Quantity; i++) { Queue.Enqueue(recipe); - _userInterface.SendMessage(new LatheFullQueueMessage(GetIDQueue())); + UserInterface?.SendMessage(new LatheFullQueueMessage(GetIdQueue())); } break; - case LatheSyncRequestMessage msg: - if (!Owner.TryGetComponent(out MaterialStorageComponent storage)) return; - _userInterface.SendMessage(new LatheFullQueueMessage(GetIDQueue())); + case LatheSyncRequestMessage _: + if (!Owner.HasComponent()) return; + UserInterface?.SendMessage(new LatheFullQueueMessage(GetIdQueue())); if (_producingRecipe != null) - _userInterface.SendMessage(new LatheProducingRecipeMessage(_producingRecipe.ID)); + UserInterface?.SendMessage(new LatheProducingRecipeMessage(_producingRecipe.ID)); break; - case LatheServerSelectionMessage msg: - if (!Owner.TryGetComponent(out ResearchClientComponent researchClient)) return; + case LatheServerSelectionMessage _: + if (!Owner.TryGetComponent(out ResearchClientComponent? researchClient)) return; researchClient.OpenUserInterface(message.Session); break; - case LatheServerSyncMessage msg: - if (!Owner.TryGetComponent(out TechnologyDatabaseComponent database) - || !Owner.TryGetComponent(out ProtolatheDatabaseComponent protoDatabase)) return; + case LatheServerSyncMessage _: + if (!Owner.TryGetComponent(out TechnologyDatabaseComponent? database) + || !Owner.TryGetComponent(out ProtolatheDatabaseComponent? protoDatabase)) return; if (database.SyncWithServer()) protoDatabase.Sync(); @@ -103,9 +108,9 @@ namespace Content.Server.GameObjects.Components.Research { 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; _producingRecipe = recipe; @@ -116,7 +121,7 @@ namespace Content.Server.GameObjects.Components.Research storage.RemoveMaterial(material, amount); } - _userInterface.SendMessage(new LatheProducingRecipeMessage(recipe.ID)); + UserInterface?.SendMessage(new LatheProducingRecipeMessage(recipe.ID)); State = LatheState.Producing; SetAppearance(LatheVisualState.Producing); @@ -126,7 +131,7 @@ namespace Content.Server.GameObjects.Components.Research Producing = false; _producingRecipe = null; Owner.EntityManager.SpawnEntity(recipe.Result, Owner.Transform.GridPosition); - _userInterface.SendMessage(new LatheStoppedProducingRecipeMessage()); + UserInterface?.SendMessage(new LatheStoppedProducingRecipeMessage()); State = LatheState.Base; SetAppearance(LatheVisualState.Idle); }); @@ -136,12 +141,12 @@ namespace Content.Server.GameObjects.Components.Research public void OpenUserInterface(IPlayerSession session) { - _userInterface.Open(session); + UserInterface?.Open(session); } void IActivate.Activate(ActivateEventArgs eventArgs) { - if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) + if (!eventArgs.User.TryGetComponent(out IActorComponent? actor)) return; if (!Powered) { @@ -153,12 +158,12 @@ namespace Content.Server.GameObjects.Components.Research async Task IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs) { - if (!Owner.TryGetComponent(out MaterialStorageComponent storage) - || !eventArgs.Using.TryGetComponent(out MaterialComponent material)) return false; + if (!Owner.TryGetComponent(out MaterialStorageComponent? storage) + || !eventArgs.Using.TryGetComponent(out MaterialComponent? material)) return false; 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; @@ -205,11 +210,13 @@ namespace Content.Server.GameObjects.Components.Research private void SetAppearance(LatheVisualState state) { - if (_appearance != null || Owner.TryGetComponent(out _appearance)) - _appearance.SetData(PowerDeviceVisuals.VisualState, state); + if (Owner.TryGetComponent(out AppearanceComponent? appearance)) + { + appearance.SetData(PowerDeviceVisuals.VisualState, state); + } } - private Queue GetIDQueue() + private Queue GetIdQueue() { var queue = new Queue(); foreach (var recipePrototype in Queue) diff --git a/Content.Server/GameObjects/Components/Research/ResearchClientComponent.cs b/Content.Server/GameObjects/Components/Research/ResearchClientComponent.cs index b57d249d3b..fb5de72bd0 100644 --- a/Content.Server/GameObjects/Components/Research/ResearchClientComponent.cs +++ b/Content.Server/GameObjects/Components/Research/ResearchClientComponent.cs @@ -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.Interfaces.GameObjects.Components; using Robust.Server.GameObjects.Components.UserInterface; @@ -14,20 +15,21 @@ namespace Content.Server.GameObjects.Components.Research [RegisterComponent] public class ResearchClientComponent : SharedResearchClientComponent, IActivate { + [Dependency] private readonly IEntitySystemManager _entitySystemManager = default!; + // TODO: Create GUI for changing RD server. - - private BoundUserInterface _userInterface; - -#pragma warning disable 649 - [Dependency] private readonly IEntitySystemManager _entitySystemManager; -#pragma warning restore 649 + private BoundUserInterface? UserInterface => + Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) && + ui.TryGetBoundUserInterface(ResearchClientUiKey.Key, out var boundUi) + ? boundUi + : null; public bool ConnectedToServer => Server != null; [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); return result; @@ -41,23 +43,28 @@ namespace Content.Server.GameObjects.Components.Research public override void Initialize() { base.Initialize(); + // For now it just registers on the first server it can find. var servers = _entitySystemManager.GetEntitySystem().Servers; - if(servers.Count > 0) + + if (servers.Count > 0) RegisterServer(servers[0]); - _userInterface = Owner.GetComponent().GetBoundUserInterface(ResearchClientUiKey.Key); - _userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; + + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; + } } public void OpenUserInterface(IPlayerSession session) { UpdateUserInterface(); - _userInterface.Open(session); + UserInterface?.Open(session); } void IActivate.Activate(ActivateEventArgs eventArgs) { - if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) + if (!eventArgs.User.TryGetComponent(out IActorComponent? actor)) return; OpenUserInterface(actor.playerSession); @@ -65,7 +72,7 @@ namespace Content.Server.GameObjects.Components.Research public void UpdateUserInterface() { - _userInterface?.SetState(GetNewUiState()); + UserInterface?.SetState(GetNewUiState()); } private ResearchClientBoundInterfaceState GetNewUiState() @@ -73,7 +80,7 @@ namespace Content.Server.GameObjects.Components.Research var rd = _entitySystemManager.GetEntitySystem(); 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) diff --git a/Content.Server/GameObjects/Components/Research/ResearchConsoleComponent.cs b/Content.Server/GameObjects/Components/Research/ResearchConsoleComponent.cs index 6d2c3380de..4c7aa4a468 100644 --- a/Content.Server/GameObjects/Components/Research/ResearchConsoleComponent.cs +++ b/Content.Server/GameObjects/Components/Research/ResearchConsoleComponent.cs @@ -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.GameObjects.Components.Research; using Content.Shared.Interfaces.GameObjects.Components; @@ -14,6 +15,7 @@ using Robust.Shared.Interfaces.Random; using Robust.Shared.IoC; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Research { @@ -21,31 +23,38 @@ namespace Content.Server.GameObjects.Components.Research [ComponentReference(typeof(IActivate))] public class ResearchConsoleComponent : SharedResearchConsoleComponent, IActivate { + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IRobustRandom _random = default!; -#pragma warning disable 649 - [Dependency] private readonly IPrototypeManager _prototypeManager; - [Dependency] private readonly IRobustRandom _random; -#pragma warning restore 649 + private const string SoundCollectionName = "keyboard"; - private BoundUserInterface _userInterface; - private ResearchClientComponent _client; - private PowerReceiverComponent _powerReceiver; - private const string _soundCollectionName = "keyboard"; + 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(ResearchConsoleUiKey.Key, out var boundUi) + ? boundUi + : null; public override void Initialize() { base.Initialize(); - _userInterface = Owner.GetComponent().GetBoundUserInterface(ResearchConsoleUiKey.Key); - _userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; - _client = Owner.GetComponent(); - _powerReceiver = Owner.GetComponent(); + + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; + } + + Owner.EnsureComponent(); } 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) return; @@ -54,8 +63,9 @@ namespace Content.Server.GameObjects.Components.Research case ConsoleUnlockTechnologyMessage msg: var protoMan = IoCManager.Resolve(); if (!protoMan.TryIndex(msg.Id, out TechnologyPrototype tech)) break; - if(!_client.Server.CanUnlockTechnology(tech)) break; - if (_client.Server.UnlockTechnology(tech)) + if (client.Server == null) break; + if (!client.Server.CanUnlockTechnology(tech)) break; + if (client.Server.UnlockTechnology(tech)) { database.SyncWithServer(); database.Dirty(); @@ -64,13 +74,12 @@ namespace Content.Server.GameObjects.Components.Research break; - case ConsoleServerSyncMessage msg: + case ConsoleServerSyncMessage _: database.SyncWithServer(); UpdateUserInterface(); break; - case ConsoleServerSelectionMessage msg: - if (!Owner.TryGetComponent(out ResearchClientComponent client)) break; + case ConsoleServerSelectionMessage _: client.OpenUserInterface(message.Session); break; } @@ -81,13 +90,17 @@ namespace Content.Server.GameObjects.Components.Research /// public void UpdateUserInterface() { - _userInterface.SetState(GetNewUiState()); + UserInterface?.SetState(GetNewUiState()); } private ResearchConsoleBoundInterfaceState GetNewUiState() { - var points = _client.ConnectedToServer ? _client.Server.Point : 0; - var pointsPerSecond = _client.ConnectedToServer ? _client.Server.PointsPerSecond : 0; + if (!Owner.TryGetComponent(out ResearchClientComponent? client) || + 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); } @@ -98,12 +111,12 @@ namespace Content.Server.GameObjects.Components.Research /// Session where the UI will be shown public void OpenUserInterface(IPlayerSession session) { - _userInterface.Open(session); + UserInterface?.Open(session); } void IActivate.Activate(ActivateEventArgs eventArgs) { - if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) + if (!eventArgs.User.TryGetComponent(out IActorComponent? actor)) return; if (!Powered) { @@ -112,17 +125,14 @@ namespace Content.Server.GameObjects.Components.Research OpenUserInterface(actor.playerSession); PlayKeyboardSound(); - return; } private void PlayKeyboardSound() { - var soundCollection = _prototypeManager.Index(_soundCollectionName); + var soundCollection = _prototypeManager.Index(SoundCollectionName); var file = _random.Pick(soundCollection.PickFiles); var audioSystem = EntitySystem.Get(); audioSystem.PlayFromEntity(file,Owner,AudioParams.Default); } - - } } diff --git a/Content.Server/GameObjects/Components/Research/ResearchServerComponent.cs b/Content.Server/GameObjects/Components/Research/ResearchServerComponent.cs index cf3811f8f2..4b117a7f7f 100644 --- a/Content.Server/GameObjects/Components/Research/ResearchServerComponent.cs +++ b/Content.Server/GameObjects/Components/Research/ResearchServerComponent.cs @@ -73,7 +73,7 @@ namespace Content.Server.GameObjects.Components.Research base.Initialize(); Id = ServerCount++; EntitySystem.Get()?.RegisterServer(this); - Database = Owner.GetComponent(); + Database = Owner.EnsureComponent(); Owner.TryGetComponent(out _powerReceiver); } diff --git a/Content.Server/GameObjects/Components/Rotatable/FlippableComponent.cs b/Content.Server/GameObjects/Components/Rotatable/FlippableComponent.cs index ad524e517c..43bd0ac6c2 100644 --- a/Content.Server/GameObjects/Components/Rotatable/FlippableComponent.cs +++ b/Content.Server/GameObjects/Components/Rotatable/FlippableComponent.cs @@ -14,9 +14,7 @@ namespace Content.Server.GameObjects.Components.Rotatable [RegisterComponent] public class FlippableComponent : Component { -#pragma warning disable 649 [Dependency] private readonly IServerNotifyManager _notifyManager = default!; -#pragma warning restore 649 public override string Name => "Flippable"; diff --git a/Content.Server/GameObjects/Components/VendingMachines/VendingMachineComponent.cs b/Content.Server/GameObjects/Components/VendingMachines/VendingMachineComponent.cs index 6929d9f981..2e1d47a898 100644 --- a/Content.Server/GameObjects/Components/VendingMachines/VendingMachineComponent.cs +++ b/Content.Server/GameObjects/Components/VendingMachines/VendingMachineComponent.cs @@ -1,8 +1,8 @@ -using System; +#nullable enable +using System; using System.Collections.Generic; using System.Linq; using Content.Server.GameObjects.Components.Power.ApcNetComponents; -using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects.Components.VendingMachines; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces.GameObjects.Components; @@ -29,27 +29,28 @@ namespace Content.Server.GameObjects.Components.VendingMachines [ComponentReference(typeof(IActivate))] public class VendingMachineComponent : SharedVendingMachineComponent, IActivate, IExamine, IBreakAct, IWires { -#pragma warning disable 649 - [Dependency] private readonly IRobustRandom _random; -#pragma warning restore 649 - private AppearanceComponent _appearance; - private BoundUserInterface _userInterface; - private PowerReceiverComponent _powerReceiver; + [Dependency] private readonly IRobustRandom _random = default!; - private bool _ejecting = false; + private bool _ejecting; private TimeSpan _animationDuration = TimeSpan.Zero; - private string _packPrototypeId; - private string _description; - private string _spriteName; + private string _packPrototypeId = ""; + private string? _description; + private string _spriteName = ""; - private bool Powered => _powerReceiver.Powered; - private bool _broken = false; + private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered; + 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) { - if(!eventArgs.User.TryGetComponent(out IActorComponent actor)) + if(!eventArgs.User.TryGetComponent(out IActorComponent? actor)) { return; } @@ -62,7 +63,7 @@ namespace Content.Server.GameObjects.Components.VendingMachines wires.OpenInterface(actor.playerSession); } else { - _userInterface.Open(actor.playerSession); + UserInterface?.Open(actor.playerSession); } } @@ -106,25 +107,32 @@ namespace Content.Server.GameObjects.Components.VendingMachines public override void Initialize() { base.Initialize(); - _appearance = Owner.GetComponent(); - _userInterface = Owner.GetComponent() - .GetBoundUserInterface(VendingMachineUiKey.Key); - _userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; - _powerReceiver = Owner.GetComponent(); - _powerReceiver.OnPowerStateChanged += UpdatePower; - TrySetVisualState(_powerReceiver.Powered ? VendingMachineVisualState.Normal : VendingMachineVisualState.Off); + + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; + } + + if (Owner.TryGetComponent(out PowerReceiverComponent? receiver)) + { + receiver.OnPowerStateChanged += UpdatePower; + TrySetVisualState(receiver.Powered ? VendingMachineVisualState.Normal : VendingMachineVisualState.Off); + } + InitializeFromPrototype(); } public override void OnRemove() { - _appearance = null; - _powerReceiver.OnPowerStateChanged -= UpdatePower; - _powerReceiver = null; + if (Owner.TryGetComponent(out PowerReceiverComponent? receiver)) + { + receiver.OnPowerStateChanged -= UpdatePower; + } + base.OnRemove(); } - private void UpdatePower(object sender, PowerStateEventArgs args) + private void UpdatePower(object? sender, PowerStateEventArgs args) { var state = args.Powered ? VendingMachineVisualState.Normal : VendingMachineVisualState.Off; TrySetVisualState(state); @@ -141,8 +149,8 @@ namespace Content.Server.GameObjects.Components.VendingMachines case VendingMachineEjectMessage msg: TryEject(msg.ID); break; - case InventorySyncRequestMessage msg: - _userInterface.SendMessage(new VendingMachineInventoryMessage(Inventory)); + case InventorySyncRequestMessage _: + UserInterface?.SendMessage(new VendingMachineInventoryMessage(Inventory)); break; } } @@ -160,7 +168,7 @@ namespace Content.Server.GameObjects.Components.VendingMachines return; } - VendingMachineInventoryEntry entry = Inventory.Find(x => x.ID == id); + var entry = Inventory.Find(x => x.ID == id); if (entry == null) { FlickDenyAnimation(); @@ -175,7 +183,7 @@ namespace Content.Server.GameObjects.Components.VendingMachines _ejecting = true; entry.Amount--; - _userInterface.SendMessage(new VendingMachineInventoryMessage(Inventory)); + UserInterface?.SendMessage(new VendingMachineInventoryMessage(Inventory)); TrySetVisualState(VendingMachineVisualState.Eject); Timer.Spawn(_animationDuration, () => @@ -204,14 +212,20 @@ namespace Content.Server.GameObjects.Components.VendingMachines if (_broken) { finalState = VendingMachineVisualState.Broken; - } else if (_ejecting) + } + else if (_ejecting) { finalState = VendingMachineVisualState.Eject; - } else if (!Powered) + } + else if (!Powered) { finalState = VendingMachineVisualState.Off; } - _appearance.SetData(VendingMachineVisuals.VisualState, finalState); + + if (Owner.TryGetComponent(out AppearanceComponent? appearance)) + { + appearance.SetData(VendingMachineVisuals.VisualState, finalState); + } } public void OnBreak(BreakageEventArgs eventArgs) diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerRangedBarrelComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerRangedBarrelComponent.cs index aca55f1921..dfc2f61b8a 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerRangedBarrelComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerRangedBarrelComponent.cs @@ -158,7 +158,8 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels { base.OnAdd(); var rangedWeaponComponent = Owner.GetComponent(); - rangedWeaponComponent.Barrel = this; + + rangedWeaponComponent.Barrel ??= this; rangedWeaponComponent.FireHandler += Fire; rangedWeaponComponent.WeaponCanFireHandler += WeaponCanFire; } diff --git a/Content.Server/GameObjects/Components/WiresComponent.cs b/Content.Server/GameObjects/Components/WiresComponent.cs index 6867052599..aa8120e16e 100644 --- a/Content.Server/GameObjects/Components/WiresComponent.cs +++ b/Content.Server/GameObjects/Components/WiresComponent.cs @@ -33,13 +33,11 @@ namespace Content.Server.GameObjects.Components [RegisterComponent] public class WiresComponent : SharedWiresComponent, IInteractUsing, IExamine, IMapInit { -#pragma warning disable 649 [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IServerNotifyManager _notifyManager = default!; -#pragma warning restore 649 + private AudioSystem _audioSystem = default!; private AppearanceComponent _appearance = default!; - private BoundUserInterface _userInterface = default!; private bool _isPanelOpen; @@ -140,15 +138,23 @@ namespace Content.Server.GameObjects.Components [ViewVariables] private string? _layoutId; + private BoundUserInterface? UserInterface => + Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) && + ui.TryGetBoundUserInterface(WiresUiKey.Key, out var boundUi) + ? boundUi + : null; + public override void Initialize() { base.Initialize(); _audioSystem = EntitySystem.Get(); _appearance = Owner.GetComponent(); _appearance.SetData(WiresVisuals.MaintenancePanelState, IsPanelOpen); - _userInterface = Owner.GetComponent() - .GetBoundUserInterface(WiresUiKey.Key); - _userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; + + if (UserInterface != null) + { + UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; + } } private void GenerateSerialNumber() @@ -357,7 +363,7 @@ namespace Content.Server.GameObjects.Components /// public void OpenInterface(IPlayerSession session) { - _userInterface.Open(session); + UserInterface?.Open(session); } private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg) @@ -450,7 +456,7 @@ namespace Content.Server.GameObjects.Components entry.Letter)); } - _userInterface.SetState( + UserInterface?.SetState( new WiresBoundUserInterfaceState( clientList.ToArray(), _statuses.Select(p => new StatusEntry(p.Key, p.Value)).ToArray(), diff --git a/Content.Server/GameObjects/EntitySystems/AI/AiSystem.cs b/Content.Server/GameObjects/EntitySystems/AI/AiSystem.cs index b04aca780e..e8470bff1e 100644 --- a/Content.Server/GameObjects/EntitySystems/AI/AiSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/AI/AiSystem.cs @@ -24,17 +24,17 @@ namespace Content.Server.GameObjects.EntitySystems.AI [Dependency] private readonly IReflectionManager _reflectionManager = default!; private readonly Dictionary _processorTypes = new Dictionary(); - + /// /// To avoid iterating over dead AI continuously they can wake and sleep themselves when necessary. /// private readonly HashSet _awakeAi = new HashSet(); - + // To avoid modifying awakeAi while iterating over it. private readonly List _queuedSleepMessages = new List(); public bool IsAwake(AiLogicProcessor processor) => _awakeAi.Contains(processor); - + /// public override void Initialize() { @@ -66,9 +66,9 @@ namespace Content.Server.GameObjects.EntitySystems.AI break; } } - + _queuedSleepMessages.Clear(); - + foreach (var processor in _awakeAi) { processor.Update(frameTime); @@ -87,7 +87,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI /// 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.SelfEntity = controller.Owner; controller.Processor.Setup(); diff --git a/Content.Server/GameObjects/EntitySystems/Atmos/GasTileOverlaySystem.cs b/Content.Server/GameObjects/EntitySystems/Atmos/GasTileOverlaySystem.cs index 96f93bb722..47f0bc50f3 100644 --- a/Content.Server/GameObjects/EntitySystems/Atmos/GasTileOverlaySystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Atmos/GasTileOverlaySystem.cs @@ -153,13 +153,20 @@ namespace Content.Server.GameObjects.EntitySystems.Atmos private bool TryRefreshTile(GridAtmosphereComponent gam, GasOverlayData oldTile, MapIndices indices, out GasOverlayData overlayData) { var tile = gam.GetTile(indices); + + if (tile == null) + { + overlayData = default; + return false; + } + var tileData = new List(); for (byte i = 0; i < Atmospherics.TotalNumberOfGases; i++) { var gas = Atmospherics.GetGas(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]; @@ -169,7 +176,7 @@ namespace Content.Server.GameObjects.EntitySystems.Atmos 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)) { diff --git a/Content.Server/GameObjects/EntitySystems/MoverSystem.cs b/Content.Server/GameObjects/EntitySystems/MoverSystem.cs index 41ded38a03..31087803c6 100644 --- a/Content.Server/GameObjects/EntitySystems/MoverSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/MoverSystem.cs @@ -30,13 +30,11 @@ namespace Content.Server.GameObjects.EntitySystems [UsedImplicitly] internal class MoverSystem : SharedMoverSystem { -#pragma warning disable 649 [Dependency] private readonly IPauseManager _pauseManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!; [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IRobustRandom _robustRandom = default!; -#pragma warning restore 649 private AudioSystem _audioSystem = default!; diff --git a/Content.Shared/GameObjects/Components/Damage/DamageableComponent.cs b/Content.Shared/GameObjects/Components/Damage/DamageableComponent.cs index f621c3f636..8557e738df 100644 --- a/Content.Shared/GameObjects/Components/Damage/DamageableComponent.cs +++ b/Content.Shared/GameObjects/Components/Damage/DamageableComponent.cs @@ -21,9 +21,7 @@ namespace Content.Shared.GameObjects.Components.Damage [ComponentReference(typeof(IDamageableComponent))] public class DamageableComponent : Component, IDamageableComponent { -#pragma warning disable 649 [Dependency] private readonly IPrototypeManager _prototypeManager = default!; -#pragma warning restore 649 public override string Name => "Damageable"; diff --git a/Content.Shared/GameObjects/Components/Movement/SharedSlipperyComponent.cs b/Content.Shared/GameObjects/Components/Movement/SharedSlipperyComponent.cs index 4d05195dba..d83b7b89d9 100644 --- a/Content.Shared/GameObjects/Components/Movement/SharedSlipperyComponent.cs +++ b/Content.Shared/GameObjects/Components/Movement/SharedSlipperyComponent.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using Content.Shared.GameObjects.Components.Mobs; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Physics; @@ -7,6 +8,7 @@ using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; +using Robust.Shared.Physics; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -116,12 +118,18 @@ namespace Content.Shared.GameObjects.Components.Movement public override void Initialize() { base.Initialize(); - var collidable = Owner.GetComponent(); + + var collidable = Owner.EnsureComponent(); collidable.Hard = false; - var shape = collidable.PhysicsShapes[0]; - shape.CollisionLayer |= (int) CollisionGroup.SmallImpassable; - shape.CollisionMask = (int)CollisionGroup.None; + + var shape = collidable.PhysicsShapes.FirstOrDefault(); + + if (shape != null) + { + shape.CollisionLayer |= (int) CollisionGroup.SmallImpassable; + shape.CollisionMask = (int) CollisionGroup.None; + } } public override void ExposeData(ObjectSerializer serializer) diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings index ac230e6680..632333c3cc 100644 --- a/SpaceStation14.sln.DotSettings +++ b/SpaceStation14.sln.DotSettings @@ -66,6 +66,7 @@ <data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="Lidgren.Network" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data> True True + True True True True