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

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

Also fix all the exceptions that happened because of this

* Add comments to the test

* Fix nullable errors

* Fix more nullable errors

* More nullable error fixes

* Unignore basic actor component

* Fix more nullable errors

* NULLABLE ERROR

* Add string interpolation

* Merge if checks

* Remove redundant pragma warning disable 649

* Address reviews

* Remove null wrappers around TryGetComponent

* Merge conflict fixes

* APC battery component error fix

* Fix power test

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

View File

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

View File

@@ -27,13 +27,9 @@ namespace Content.Client.GameObjects.Components.Instruments
/// </summary>
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;

View File

@@ -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
/// <inheritdoc />
private readonly List<Hand> _hands = new List<Hand>();

View File

@@ -1,16 +1,11 @@
using System.IO;
using System.Threading.Tasks;
using System.Threading.Tasks;
using Content.Server.GameObjects.Components.Doors;
using Content.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

View File

@@ -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<IPauseManager>();
var prototypes = new List<EntityPrototype>();
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<IMapManager>();
var entityManager = server.ResolveDependency<IEntityManager>();
var mapLoader = server.ResolveDependency<IMapLoader>();
var pauseManager = server.ResolveDependency<IPauseManager>();
var componentFactory = server.ResolveDependency<IComponentFactory>();
var prototypeManager = server.ResolveDependency<IPrototypeManager>();
IMapGrid grid = default;
server.Post(() =>
{
// Load test entity
using var reader = new StringReader(testEntity);
prototypeManager.LoadFromStream(reader);
// Load test map
var mapId = mapManager.CreateMap();
pauseManager.AddUninitializedMap(mapId);
grid = mapLoader.LoadBlueprint(mapId, "Maps/stationstation.yml");
pauseManager.DoMapInitialize(mapId);
});
var distinctComponents = new List<(List<Type> components, List<Type> references)>
{
(new List<Type>(), new List<Type>())
};
// Split components into groups, ensuring that their references don't conflict
foreach (var type in componentFactory.AllRegisteredTypes)
{
var registration = componentFactory.GetRegistration(type);
for (var i = 0; i < distinctComponents.Count; i++)
{
var distinct = distinctComponents[i];
if (distinct.references.Intersect(registration.References).Any())
{
// Ensure the next list if this one has conflicting references
if (i + 1 >= distinctComponents.Count)
{
distinctComponents.Add((new List<Type>(), new List<Type>()));
}
continue;
}
// Add the component and its references if no conflicting references were found
distinct.components.Add(type);
distinct.references.AddRange(registration.References);
}
}
// Sanity check
Assert.That(distinctComponents, Is.Not.Empty);
server.Assert(() =>
{
Assert.DoesNotThrow(() =>
{
foreach (var distinct in distinctComponents)
{
var testLocation = new GridCoordinates(new Vector2(0, 0), grid);
var entity = entityManager.SpawnEntity("AllComponentsOneEntityDeleteTestEntity", testLocation);
Assert.That(entity.Initialized);
foreach (var type in distinct.components)
{
var component = (Component) componentFactory.GetComponent(type);
// If the entity already has this component, if it was ensured or added by another
if (entity.HasComponent(component.GetType()))
{
continue;
}
// If this component is ignored
if (skipComponents.Contains(component.Name))
{
continue;
}
component.Owner = entity;
Logger.LogS(LogLevel.Debug, "EntityTest", $"Adding component: {component.Name}");
entityManager.ComponentManager.AddComponent(entity, component);
}
server.RunTicks(48); // Run one full second on the server
entityManager.DeleteEntity(entity.Uid);
}
});
});
await server.WaitIdleAsync();
}
}
}

View File

@@ -127,6 +127,7 @@ namespace Content.IntegrationTests.Tests
Assert.That(apcEnt.TryGetComponent<ApcComponent>(out var apc));
Assert.That(apcExtensionEnt.TryGetComponent<PowerProviderComponent>(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

View File

@@ -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";

View File

@@ -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<ContainerSlot>($"{Name}-privilegedId", Owner);
_targetIdContainer = ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-targetId", Owner);
_accessReader = Owner.GetComponent<AccessReader>();
if (!Owner.EnsureComponent(out AccessReader _))
{
Logger.Warning($"Entity {Owner} at {Owner.Transform.MapPosition} didn't have a {nameof(AccessReader)}");
}
if (UserInterface == null)
{
Logger.Warning($"Entity {Owner} at {Owner.Transform.MapPosition} doesn't have a {nameof(ServerUserInterfaceComponent)}");
}
else
{
UserInterface.OnReceiveMessage += OnUiReceiveMessage;
}
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(IdCardConsoleUiKey.Key);
_userInterface.OnReceiveMessage += OnUiReceiveMessage;
UpdateUserInterface();
}
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
}
/// <summary>
/// Returns true if there is an ID in <see cref="_privilegedIdContainer"/> and said ID satisfies the requirements of <see cref="_accessReader"/>.
/// Returns true if there is an ID in <see cref="_privilegedIdContainer"/> and said ID satisfies the requirements of <see cref="AccessReader"/>.
/// </summary>
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);
}
/// <summary>
/// Called when the "Submit" button in the UI gets pressed.
/// Writes data passed from the UI into the ID stored in <see cref="_targetIdContainer"/>, if present.
@@ -110,7 +135,7 @@ namespace Content.Server.GameObjects.Components.Access
/// </summary>
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);
}
}
}

View File

@@ -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<AtmosphereSystem>().GetGridAtmosphere(Owner.Transform.GridID)?.Invalidate(_snapGrid.Position);
if (Owner.TryGetComponent(out SnapGridComponent? snapGrid))
{
EntitySystem.Get<AtmosphereSystem>().GetGridAtmosphere(Owner.Transform.GridID)?.Invalidate(snapGrid.Position);
}
}
}
@@ -48,19 +52,23 @@ namespace Content.Server.GameObjects.Components.Atmos
base.Initialize();
// 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<AtmosphereSystem>().GetGridAtmosphere(Owner.Transform.GridID)?
.FixVacuum(snapGrid.Position);
}
if(_fixVacuum)
EntitySystem.Get<AtmosphereSystem>().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<AtmosphereSystem>().GetGridAtmosphere(gridId)?.Invalidate(pos);
}
}
}

View File

@@ -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<ServerUserInterfaceComponent>()
.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<GasEntry>();
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,

View File

@@ -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);
}
}
}

View File

@@ -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<ExcitedGroup> _excitedGroups = new HashSet<ExcitedGroup>(1000);
@@ -89,42 +89,40 @@ namespace Content.Server.GameObjects.Components.Atmos
/// <inheritdoc />
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<ITileDefinitionManager>();
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<IServerEntityManager>().SpawnEntity(tileDef.ItemDropPrototypeName, new GridCoordinates(indices.X, indices.Y, _grid));
var tileItem = IoCManager.Resolve<IServerEntityManager>().SpawnEntity(tileDef.ItemDropPrototypeName, new GridCoordinates(indices.X, indices.Y, mapGrid));
tileItem.Transform.WorldPosition += (0.2f, 0.2f);
}
public override void Initialize()
{
base.Initialize();
_grid = Owner.GetComponent<IMapGridComponent>().Grid;
RepopulateTiles();
}
public override void OnAdd()
{
base.OnAdd();
_grid = Owner.GetComponent<IMapGridComponent>().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
/// <inheritdoc />
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
/// <inheritdoc />
[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);
}
/// <inheritdoc />
[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
/// <inheritdoc />
[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);
}
/// <inheritdoc />
[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
/// <inheritdoc />
[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
}
/// <inheritdoc />
public TileAtmosphere GetTile(GridCoordinates coordinates)
public TileAtmosphere? GetTile(GridCoordinates coordinates)
{
return GetTile(coordinates.ToMapIndices(_mapManager));
}
/// <inheritdoc />
public TileAtmosphere GetTile(MapIndices indices)
public TileAtmosphere? GetTile(MapIndices indices)
{
if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return null;
if (_tiles.TryGetValue(indices, out var tile)) return tile;
// 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<Direction, TileAtmosphere> 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
/// <inheritdoc />
public float GetVolumeForCells(int cellCount)
{
return _grid.TileSize * cellCount * Atmospherics.CellVolume;
if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return default;
return mapGrid.Grid.TileSize * cellCount * Atmospherics.CellVolume;
}
/// <inheritdoc />
@@ -509,9 +520,11 @@ namespace Content.Server.GameObjects.Components.Atmos
}
}
private AirtightComponent GetObstructingComponent(MapIndices indices)
private AirtightComponent? GetObstructingComponent(MapIndices indices)
{
foreach (var v in _grid.GetSnapGridCell(indices, SnapGridOffset.Center))
if (!Owner.TryGetComponent(out IMapGridComponent? mapGrid)) return default;
foreach (var v in mapGrid.Grid.GetSnapGridCell(indices, SnapGridOffset.Center))
{
if (v.Owner.TryGetComponent<AirtightComponent>(out var ac))
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<IMapGridComponent>().Grid.Index;
var gridId = mapGrid.Grid.Index;
if (!serializer.TryReadDataField("uniqueMixes", out List<GasMixture> uniqueMixes) ||
!serializer.TryReadDataField("tiles", out Dictionary<MapIndices, int> tiles))
if (!serializer.TryReadDataField("uniqueMixes", out List<GasMixture>? uniqueMixes) ||
!serializer.TryReadDataField("tiles", out Dictionary<MapIndices, int>? 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<GasMixture>();
var uniqueMixHash = new Dictionary<GasMixture, int>();

View File

@@ -1,4 +1,5 @@
using System.Linq;
#nullable enable
using System.Linq;
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
using 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<PowerReceiverComponent>();
_sprite = Owner.GetComponent<SpriteComponent>();
_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();
}

View File

@@ -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<ServerUserInterfaceComponent>()
.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) { }

View File

@@ -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
/// <summary>
/// Max volume of internal solution storage
/// </summary>
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;
}
}
}
/// <summary>
/// Internal solution storage
/// </summary>
[ViewVariables]
private SolutionComponent _stomachContents;
/// <summary>
/// Initial internal solution storage volume
/// </summary>
@@ -68,20 +63,29 @@ namespace Content.Server.GameObjects.Components.Body.Digestive
{
base.Startup();
_stomachContents = Owner.GetComponent<SolutionComponent>();
_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
/// <param name="frameTime">The time since the last update in seconds.</param>
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);
}

View File

@@ -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<int, object> _optionsCache = new Dictionary<int, object>();
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<ServerUserInterfaceComponent>()
.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
/// </summary>
private void HandleReceiveBodyPartSlot(int key)
{
CloseSurgeryUI(_performerCache.GetComponent<BasicActorComponent>().playerSession);
if (_performerCache == null ||
!_performerCache.TryGetComponent(out IActorComponent? actor))
{
return;
}
CloseSurgeryUI(actor.playerSession);
if (_bodyManagerComponentCache == null)
{
return;
}
// TODO: sanity checks to see whether user is in range, user is still able-bodied, target is still the same, etc etc
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<string, int> 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)

View File

@@ -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<int, object> _optionsCache = new Dictionary<int, object>();
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<DroppedBodyPartComponent>(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<ServerUserInterfaceComponent>()
.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
/// </summary>
private void HandleReceiveBodyPart(int key)
{
CloseSurgeryUI(_performerCache.GetComponent<BasicActorComponent>().playerSession);
if (_performerCache == null ||
!_performerCache.TryGetComponent(out IActorComponent? actor))
{
return;
}
CloseSurgeryUI(actor.playerSession);
if (_bodyManagerComponentCache == null)
{
return;
}
// TODO: sanity checks to see whether user is in range, user is still able-bodied, target is still the same, etc etc
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<string, int> 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)

View File

@@ -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<string, int>();
@@ -105,13 +111,7 @@ namespace Content.Server.GameObjects.Components.Body
// Attempt surgery on a DroppedBodyPart - there's only one possible target so no need for selection UI
_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<BasicActorComponent>().playerSession);
UpdateSurgeryUIMechanismRequest(_performerCache.GetComponent<BasicActorComponent>().playerSession,
@@ -162,34 +162,35 @@ namespace Content.Server.GameObjects.Components.Body
{
base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.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<string, int> options)
{
_userInterface.SendMessage(new RequestBodyPartSurgeryUIMessage(options), session);
UserInterface?.SendMessage(new RequestBodyPartSurgeryUIMessage(options), session);
}
private void UpdateSurgeryUIMechanismRequest(IPlayerSession session, Dictionary<string, int> options)
{
_userInterface.SendMessage(new RequestMechanismSurgeryUIMessage(options), session);
UserInterface?.SendMessage(new RequestMechanismSurgeryUIMessage(options), session);
}
private void CloseSurgeryUI(IPlayerSession session)
{
_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
/// </summary>
private void HandleReceiveBodyPart(int key)
{
CloseSurgeryUI(_performerCache.GetComponent<BasicActorComponent>().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<BasicActorComponent>().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,

View File

@@ -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;

View File

@@ -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<GalacticMarketComponent>();
Orders = Owner.GetComponent<CargoOrderDatabaseComponent>();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(CargoConsoleUiKey.Key);
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
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<CargoConsoleSystem>();
BankAccount = _cargoConsoleSystem.StationAccount;
}
public override void OnRemove()
{
if (UserInterface != null)
{
UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
}
base.OnRemove();
}
/// <summary>
/// Reads data from YAML
/// </summary>
@@ -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));
}
}
}

View File

@@ -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;
/// <summary>
/// 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<ServerUserInterfaceComponent>()
.GetBoundUserInterface(ChemMasterUiKey.Key);
_userInterface.OnReceiveMessage += OnUiReceiveMessage;
if (UserInterface != null)
{
UserInterface.OnReceiveMessage += OnUiReceiveMessage;
}
_beakerContainer =
ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-reagentContainerContainer", Owner);
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
_powerReceiver.OnPowerStateChanged += OnPowerChanged;
if (Owner.TryGetComponent(out PowerReceiverComponent? receiver))
{
receiver.OnPowerStateChanged += OnPowerChanged;
}
//BufferSolution = Owner.BufferSolution
BufferSolution.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
/// <param name="obj">A user interface message from the client.</param>
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
/// </summary>
/// <param name="playerEntity">The player entity.</param>
/// <returns>Returns true if the entity can use the chem master, and false if it cannot.</returns>
private bool PlayerCanUseChemMaster(IEntity playerEntity, bool needsPower = true)
private bool PlayerCanUseChemMaster(IEntity? playerEntity, bool needsPower = true)
{
//Need player entity to check if they are still able to use the chem master
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<Solution.ReagentQuantity>(), BufferSolution.ReagentList.ToList(), _bufferModeTransfer, BufferSolution.CurrentVolume, BufferSolution.MaxVolume);
}
var solution = beaker.GetComponent<SolutionComponent>();
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);
}
/// <summary>
@@ -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<SolutionComponent>();
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
/// <param name="args">Data relevant to the event such as the actor which triggered it.</param>
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
/// <returns></returns>
async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs args)
{
if (!args.User.TryGetComponent(out IHandsComponent hands))
if (!args.User.TryGetComponent(out IHandsComponent? hands))
{
_notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User,
_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<SolutionComponent>(out var solution))
{

View File

@@ -1,4 +1,5 @@
using System;
#nullable enable
using System;
using Content.Server.GameObjects.Components.Body.Circulatory;
using Content.Server.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!;
/// <summary>
/// Whether or not the injector is able to draw from containers or if it's a single use
@@ -53,11 +52,6 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
private InjectorToggleMode _toggleState;
/// <summary>
/// Internal solution container
/// </summary>
[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<SolutionComponent>();
_internalContents.Capabilities |= SolutionCaps.Injector;
//Set _toggleState based on prototype
Owner.EnsureComponent<SolutionComponent>();
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);
}
}
}

View File

@@ -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<SolutionComponent>();
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;
/// <summary>
/// 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<ServerUserInterfaceComponent>()
.GetBoundUserInterface(ReagentDispenserUiKey.Key);
_userInterface.OnReceiveMessage += OnUiReceiveMessage;
if (UserInterface != null)
{
UserInterface.OnReceiveMessage += OnUiReceiveMessage;
}
_beakerContainer =
ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-reagentContainerContainer", Owner);
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
_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
/// <param name="obj">A user interface message from the client.</param>
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
/// </summary>
/// <param name="playerEntity">The player entity.</param>
/// <returns>Returns true if the entity can use the dispenser, and false if it cannot.</returns>
private bool PlayerCanUseDispenser(IEntity playerEntity, bool needsPower = true)
private bool PlayerCanUseDispenser(IEntity? playerEntity, bool needsPower = true)
{
//Need player entity to check if they are still able to use the dispenser
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);
}
/// <summary>
@@ -265,12 +278,12 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// <param name="args">Data relevant to the event such as the actor which triggered it.</param>
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
/// <returns></returns>
async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs args)
{
if (!args.User.TryGetComponent(out IHandsComponent hands))
if (!args.User.TryGetComponent(out IHandsComponent? hands))
{
_notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User,
_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<SolutionComponent>(out var solution))
{

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.EntitySystems;
#nullable enable
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.Chemistry;
using 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<SpriteComponent>();
_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<SolutionComponent>().Capabilities |= SolutionCaps.FitsInDispenser;;
Owner.GetComponent<SolutionComponent>().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;
}
}
}

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
#nullable enable
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
using Content.Server.GameObjects.EntitySystems;
using Content.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<RoundEndSystem>();
[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<ServerUserInterfaceComponent>().GetBoundUserInterface(CommunicationsConsoleUiKey.Key);
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
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)

View File

@@ -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";

View File

@@ -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<ToolQuality>());
}
public override void Initialize()
{
base.Initialize();
Owner.EnsureComponent<DestructibleComponent>();
}
public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs)
{
if (eventArgs.Using.TryGetComponent<ToolComponent>(out var tool))
@@ -56,7 +51,7 @@ namespace Content.Server.GameObjects.Components.Damage
protected bool CallDamage(InteractUsingEventArgs eventArgs, ToolComponent tool)
{
if (eventArgs.Target.TryGetComponent<DestructibleComponent>(out var damageable))
if (eventArgs.Target.TryGetComponent<IDamageableComponent>(out var damageable))
{
damageable.ChangeDamage(tool.HasQuality(ToolQuality.Welding)
? DamageType.Heat

View File

@@ -1,4 +1,5 @@
using Content.Server.Interfaces;
#nullable enable
using Content.Server.Interfaces;
using Content.Server.Interfaces.GameObjects.Components.Items;
using Content.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<string> _tags;
private readonly HashSet<string> _tags = new HashSet<string>();
[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<ServerUserInterfaceComponent>()
.GetBoundUserInterface(DisposalRouterUiKey.Key);
_userInterface.OnReceiveMessage += OnUiReceiveMessage;
_tags = new HashSet<string>();
if (UserInterface != null)
{
UserInterface.OnReceiveMessage += OnUiReceiveMessage;
}
UpdateUserInterface();
}
@@ -73,6 +75,11 @@ namespace Content.Server.GameObjects.Components.Disposal
/// <param name="obj">A user interface message from the client.</param>
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
/// <summary>
/// Gets component data to be used to update the user interface client-side.
/// </summary>
/// <returns>Returns a <see cref="SharedDisposalRouterComponent.DisposalRouterBoundUserInterfaceState"/></returns>
/// <returns>Returns a <see cref="DisposalRouterUserInterfaceState"/></returns>
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
/// <param name="args">Data relevant to the event such as the actor which triggered it.</param>
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();
}
}

View File

@@ -1,4 +1,5 @@
using Content.Server.Interfaces;
#nullable enable
using Content.Server.Interfaces;
using Content.Server.Interfaces.GameObjects.Components.Items;
using Content.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<ServerUserInterfaceComponent>()
.GetBoundUserInterface(DisposalTaggerUiKey.Key);
_userInterface.OnReceiveMessage += OnUiReceiveMessage;
if (UserInterface != null)
{
UserInterface.OnReceiveMessage += OnUiReceiveMessage;
}
UpdateUserInterface();
}
@@ -81,7 +85,7 @@ namespace Content.Server.GameObjects.Components.Disposal
/// </summary>
/// <param name="playerEntity">The player entity.</param>
/// <returns>Returns true if the entity can use the configuration interface, and false if it cannot.</returns>
private bool PlayerCanUseDisposalTagger(IEntity playerEntity)
private bool PlayerCanUseDisposalTagger(IEntity? playerEntity)
{
//Need player entity to check if they are still able to use the configuration interface
if (playerEntity == null)
@@ -98,7 +102,7 @@ namespace Content.Server.GameObjects.Components.Disposal
/// <summary>
/// Gets component data to be used to update the user interface client-side.
/// </summary>
/// <returns>Returns a <see cref="SharedDisposalTaggerComponent.DisposalTaggerBoundUserInterfaceState"/></returns>
/// <returns>Returns a <see cref="DisposalTaggerUserInterfaceState"/></returns>
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
/// <param name="args">Data relevant to the event such as the actor which triggered it.</param>
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();
}
}
}

View File

@@ -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<IEntity> 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<Container>(Name, Owner);
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.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;
}

View File

@@ -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
/// </summary>
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<PowerReceiverComponent>();
_wires = Owner.GetComponent<WiresComponent>();
_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<bool> 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;
}
}

View File

@@ -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<AirtightComponent>();
_collidableComponent = Owner.GetComponent<ICollidableComponent>();
_appearance = Owner.GetComponent<AppearanceComponent>();
_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<AudioSystem>().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);

View File

@@ -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;
/// <inheritdoc />
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<SolutionComponent>();
Owner.EnsureComponent<SolutionComponent>();
}
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<bool> InteractUsing(InteractUsingEventArgs eventArgs)
{
if (!eventArgs.Using.TryGetComponent(out MopComponent mopComponent))
if (!Owner.TryGetComponent(out SolutionComponent? contents))
{
return false;
}
if (!eventArgs.Using.TryGetComponent(out MopComponent? mopComponent))
{
return false;
}
@@ -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();

View File

@@ -126,18 +126,25 @@ namespace Content.Server.GameObjects.Components.Fluids
_contents.Initialize();
}
_snapGrid = Owner.GetComponent<SnapGridComponent>();
_snapGrid = Owner.EnsureComponent<SnapGridComponent>();
// 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>();
_spriteComponent = Owner.EnsureComponent<SpriteComponent>();
var robustRandom = IoCManager.Resolve<IRobustRandom>();
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();

View File

@@ -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;

View File

@@ -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;

View File

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

View File

@@ -1,11 +1,10 @@
using System;
#nullable enable
using System.Collections.Generic;
using System.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<ServerUserInterfaceComponent>().GetBoundUserInterface(StrippingUiKey.Key);
_userInterface.OnReceiveMessage += HandleUserInterfaceMessage;
if (UserInterface != null)
{
UserInterface.OnReceiveMessage += HandleUserInterfaceMessage;
}
_inventoryComponent = Owner.GetComponent<InventoryComponent>();
_handsComponent = Owner.GetComponent<HandsComponent>();
Owner.EnsureComponent<InventoryComponent>();
Owner.EnsureComponent<HandsComponent>();
_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<Slots, string>();
foreach (var slot in _inventoryComponent.Slots)
if (!Owner.TryGetComponent(out InventoryComponent? inventory))
{
dictionary[slot] = _inventoryComponent.GetSlotItem(slot)?.Owner.Name ?? "None";
return dictionary;
}
foreach (var slot in inventory.Slots)
{
dictionary[slot] = inventory.GetSlotItem(slot)?.Owner.Name ?? "None";
}
return dictionary;
@@ -89,9 +103,14 @@ namespace Content.Server.GameObjects.Components.GUI
{
var dictionary = new Dictionary<string, string>();
foreach (var hand in _handsComponent.Hands)
if (!Owner.TryGetComponent(out HandsComponent? hands))
{
dictionary[hand] = _handsComponent.GetItem(hand)?.Owner.Name ?? "None";
return dictionary;
}
foreach (var hand in hands.Hands)
{
dictionary[hand] = hands.GetItem(hand)?.Owner.Name ?? "None";
}
return dictionary;
@@ -99,7 +118,7 @@ namespace Content.Server.GameObjects.Components.GUI
private void OpenUserInterface(IPlayerSession session)
{
_userInterface.Open(session);
UserInterface?.Open(session);
}
/// <summary>
@@ -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;

View File

@@ -1,8 +1,8 @@
using System.Threading.Tasks;
#nullable enable
using System.Threading.Tasks;
using Content.Server.GameObjects.Components.Damage;
using Content.Server.GameObjects.Components.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<ServerUserInterfaceComponent>()
.GetBoundUserInterface(GravityGeneratorUiKey.Key);
_userInterface.OnReceiveMessage += HandleUIMessage;
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
_sprite = Owner.GetComponent<SpriteComponent>();
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<bool> 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);
}
}
}

View File

@@ -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.
/// </summary>
[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;
/// <summary>
/// Whether the instrument is an item which can be held or not.
/// </summary>
@@ -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<ServerUserInterfaceComponent>().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();

View File

@@ -1,4 +1,5 @@
using System.Threading.Tasks;
#nullable enable
using System.Threading.Tasks;
using Content.Server.GameObjects.Components.GUI;
using Content.Server.GameObjects.Components.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<PointLightComponent>();
_spriteComponent = Owner.GetComponent<SpriteComponent>();
Owner.TryGetComponent(out _clothingComponent);
Owner.EnsureComponent<PointLightComponent>();
_cellContainer =
ContainerManagerComponent.Ensure<ContainerSlot>("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;
}

View File

@@ -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;

View File

@@ -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<StackComponent>();
Owner.EnsureComponent<StackComponent>();
}
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));

View File

@@ -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";

View File

@@ -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;
/// <summary>
@@ -67,20 +62,23 @@ namespace Content.Server.GameObjects.Components.Kitchen
/// </summary>
[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<SolutionComponent>();
Owner.EnsureComponent<SolutionComponent>();
_storage = ContainerManagerComponent.Ensure<Container>("microwave_entity_container", Owner, out var existed);
_appearance = Owner.GetComponent<AppearanceComponent>();
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
_audioSystem = EntitySystem.Get<AudioSystem>();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.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<bool> 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<string, int>();
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<string,int> 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;
}

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.Components.Mobs;
#nullable enable
using Content.Server.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.Components;
using Content.Shared.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<ServerUserInterfaceComponent>()
.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);
}
}
}

View File

@@ -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<AppearanceComponent>();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(MedicalScannerUiKey.Key);
_userInterface.OnReceiveMessage += OnUiReceiveMessage;
_bodyContainer = ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-bodyContainer", Owner);
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
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<ContainerSlot>($"{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]

View File

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

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.EntitySystems.AI;
#nullable enable
using Content.Server.GameObjects.EntitySystems.AI;
using Content.Shared.GameObjects.Components.Movement;
using 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,8 +46,7 @@ namespace Content.Server.GameObjects.Components.Movement
base.Initialize();
// This component requires a collidable component.
if (!Owner.HasComponent<ICollidableComponent>())
Owner.AddComponent<CollidableComponent>();
Owner.EnsureComponent<CollidableComponent>();
EntitySystem.Get<AiSystem>().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;
}

View File

@@ -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
/// <summary>
/// The range from which this entity can be climbed.

View File

@@ -1,4 +1,5 @@
using System;
#nullable enable
using System;
using System.Collections.Generic;
using 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<IEntity> immuneEntities = new List<IEntity>(); // K
[ViewVariables] private string _departureSound = "";
[ViewVariables] private string _arrivalSound = "";
public readonly List<IEntity> ImmuneEntities = new List<IEntity>(); // 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<AppearanceComponent>();
}
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<ServerPortalComponent>(out var otherPortal))
{
otherPortal.immuneEntities.Remove(entity);
otherPortal.ImmuneEntities.Remove(entity);
}
}
@@ -142,7 +128,7 @@ namespace Content.Server.GameObjects.Components.Movement
private bool IsEntityPortable(IEntity entity)
{
// TODO: Check if it's slotted etc. Otherwise the slot item itself gets ported.
if (!immuneEntities.Contains(entity) && entity.HasComponent<TeleportableComponent>())
if (!ImmuneEntities.Contains(entity) && entity.HasComponent<TeleportableComponent>())
{
return true;
}
@@ -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<ServerPortalComponent>().immuneEntities.Add(entity);
Timer.Spawn(TimeSpan.FromSeconds(_individualPortalCooldown), () => releaseCooldown(entity));
ImmuneEntities.Add(entity);
_connectingTeleporter.GetComponent<ServerPortalComponent>().ImmuneEntities.Add(entity);
Timer.Spawn(TimeSpan.FromSeconds(_individualPortalCooldown), () => ReleaseCooldown(entity));
StartCooldown();
}
}

View File

@@ -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<AppearanceComponent>();
_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<AudioSystem>();
// 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<ServerPortalComponent>(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<ServerPortalComponent>(out var arrivalComponent))
{
// Connect. TODO: If the OnUpdate in ServerPortalComponent is changed this may need to change as well.
arrivalComponent.TryConnectPortal(departurePortal);
}
}
else
{

View File

@@ -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;

View File

@@ -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)

View File

@@ -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<UtensilType>();
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<SolutionComponent>();
Owner.EnsureComponent<SolutionComponent>();
}
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<UtensilComponent>();
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);

View File

@@ -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<Container>("pda_entity_container", Owner, out var existed);
_pdaLight = Owner.GetComponent<PointLightComponent>();
_appearance = Owner.GetComponent<AppearanceComponent>();
_interface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(PDAUiKey.Key);
_interface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
if (UserInterface != null)
{
UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
}
var idCard = _entityManager.SpawnEntity(_startingIdCard, Owner.Transform.GridPosition);
var idCardComponent = idCard.GetComponent<IdCardComponent>();
_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<bool> 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<AudioSystem>().PlayFromEntity("/Audio/Items/flashlight_toggle.ogg", Owner);
UpdatePDAUserInterface();
}

View File

@@ -1,4 +1,5 @@
using System.Threading.Tasks;
#nullable enable
using System.Threading.Tasks;
using Content.Shared.GameObjects.Components;
using Content.Shared.GameObjects.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<ServerUserInterfaceComponent>()
.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<WriteComponent>())
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;
}
}

View File

@@ -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<BatteryComponent>();
_appearance = Owner.GetComponent<AppearanceComponent>();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(ApcUiKey.Key);
_userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
Owner.EnsureComponent<BatteryComponent>();
Owner.EnsureComponent<PowerConsumerComponent>();
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<PowerConsumerComponent>();
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);
}
}
}

View File

@@ -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<PowerReceiverComponent>();
Owner.EnsureComponent<PowerReceiverComponent>();
_container = ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-powerCellContainer", Owner);
_appearanceComponent = Owner.GetComponent<AppearanceComponent>();
// Default state in the visualizer is OFF, so when this gets powered on during initialization it will generally show empty
_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<ItemComponent>());
}
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)

View File

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

View File

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

View File

@@ -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<AppearanceComponent>();
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);
}
}
}
}

View File

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

View File

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

View File

@@ -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<BatteryComponent>();
_appearance = Owner.GetComponent<AppearanceComponent>();
Owner.EnsureComponent<BatteryComponent>();
Owner.EnsureComponent<AppearanceComponent>();
}
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()

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
#nullable enable
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
using Content.Server.GameObjects.EntitySystems;
using Content.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<ServerUserInterfaceComponent>().GetBoundUserInterface(SolarControlConsoleUiKey.Key);
_userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
if (UserInterface != null)
{
UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
}
Owner.EnsureComponent<PowerReceiverComponent>();
_powerSolarSystem = _entitySystemManager.GetEntitySystem<PowerSolarSystem>();
}
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);
}
}
}

View File

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

View File

@@ -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<ProjectileComponent>())
{
throw new InvalidOperationException();
}
Owner.EnsureComponent<ProjectileComponent>();
}
void ICollideBehavior.CollideWith(IEntity entity)

View File

@@ -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";

View File

@@ -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";

View File

@@ -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<LatheRecipePrototype> Queue { get; } = new Queue<LatheRecipePrototype>();
[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<ServerUserInterfaceComponent>().GetBoundUserInterface(LatheUiKey.Key);
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
_appearance = Owner.GetComponent<AppearanceComponent>();
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<MaterialStorageComponent>()) 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<bool> 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<string> GetIDQueue()
private Queue<string> GetIdQueue()
{
var queue = new Queue<string>();
foreach (var recipePrototype in Queue)

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.EntitySystems;
#nullable enable
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components.Research;
using Content.Shared.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<ResearchSystem>().Servers;
if(servers.Count > 0)
if (servers.Count > 0)
RegisterServer(servers[0]);
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(ResearchClientUiKey.Key);
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
if (UserInterface != null)
{
UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
}
}
public void OpenUserInterface(IPlayerSession session)
{
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<ResearchSystem>();
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)

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
#nullable enable
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
using Content.Shared.Audio;
using Content.Shared.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<ServerUserInterfaceComponent>().GetBoundUserInterface(ResearchConsoleUiKey.Key);
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
_client = Owner.GetComponent<ResearchClientComponent>();
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
if (UserInterface != null)
{
UserInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
}
Owner.EnsureComponent<ResearchClientComponent>();
}
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<IPrototypeManager>();
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
/// </summary>
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
/// <param name="session">Session where the UI will be shown</param>
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<SoundCollectionPrototype>(_soundCollectionName);
var soundCollection = _prototypeManager.Index<SoundCollectionPrototype>(SoundCollectionName);
var file = _random.Pick(soundCollection.PickFiles);
var audioSystem = EntitySystem.Get<AudioSystem>();
audioSystem.PlayFromEntity(file,Owner,AudioParams.Default);
}
}
}

View File

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

View File

@@ -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";

View File

@@ -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<AppearanceComponent>();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(VendingMachineUiKey.Key);
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
_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)

View File

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

View File

@@ -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<AudioSystem>();
_appearance = Owner.GetComponent<AppearanceComponent>();
_appearance.SetData(WiresVisuals.MaintenancePanelState, IsPanelOpen);
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(WiresUiKey.Key);
_userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
if (UserInterface != null)
{
UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
}
}
private void GenerateSerialNumber()
@@ -357,7 +363,7 @@ namespace Content.Server.GameObjects.Components
/// </summary>
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(),

View File

@@ -87,7 +87,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI
/// <param name="controller"></param>
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();

View File

@@ -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<GasData>();
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))
{

View File

@@ -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!;

View File

@@ -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";

View File

@@ -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<ICollidableComponent>();
var collidable = Owner.EnsureComponent<CollidableComponent>();
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)

View File

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