Enable nullability in Content.Shared (#3626)

* Enable nullability in Content.Shared

* Fix null errors in server

* aye github i swear on me mom
This commit is contained in:
DrSmugleaf
2021-03-15 21:55:49 +01:00
committed by GitHub
parent 04201e944c
commit 6f012cb9ad
31 changed files with 167 additions and 117 deletions

View File

@@ -6,7 +6,6 @@ using Content.Client.GameObjects.EntitySystems;
using Content.Client.UserInterface; using Content.Client.UserInterface;
using Content.Client.Utility; using Content.Client.Utility;
using Content.Shared.Construction; using Content.Shared.Construction;
using Content.Shared.GameObjects.Components;
using Content.Shared.GameObjects.Components.Interactable; using Content.Shared.GameObjects.Components.Interactable;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.Placement; using Robust.Client.Placement;
@@ -18,7 +17,6 @@ using Robust.Shared.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Client.Construction namespace Content.Client.Construction
{ {
@@ -224,15 +222,21 @@ namespace Content.Client.Construction
var startNode = graph.Nodes[prototype.StartNode]; var startNode = graph.Nodes[prototype.StartNode];
var targetNode = graph.Nodes[prototype.TargetNode]; var targetNode = graph.Nodes[prototype.TargetNode];
var path = graph.Path(startNode.Name, targetNode.Name); if (!graph.TryPath(startNode.Name, targetNode.Name, out var path))
{
return;
}
var current = startNode; var current = startNode;
var stepNumber = 1; var stepNumber = 1;
foreach (var node in path) foreach (var node in path)
{ {
var edge = current.GetEdge(node.Name); if (!current.TryGetEdge(node.Name, out var edge))
{
continue;
}
var firstNode = current == startNode; var firstNode = current == startNode;
if (firstNode) if (firstNode)

View File

@@ -165,7 +165,7 @@ namespace Content.Client.GameObjects.Components.Atmos
TemperatureHelpers.KelvinToCelsius(state.Temperature)) TemperatureHelpers.KelvinToCelsius(state.Temperature))
}); });
// Return here cause all that stuff down there is gas stuff (so we don't get the seperators) // Return here cause all that stuff down there is gas stuff (so we don't get the seperators)
if (state.Gases.Length == 0) if (state.Gases == null || state.Gases.Length == 0)
{ {
return; return;
} }

View File

@@ -27,8 +27,13 @@ namespace Content.Client.GameObjects.Components.Construction
if (!_prototypeManager.TryIndex(Prototype.Graph, out ConstructionGraphPrototype? graph)) return; if (!_prototypeManager.TryIndex(Prototype.Graph, out ConstructionGraphPrototype? graph)) return;
var startNode = graph.Nodes[Prototype.StartNode]; var startNode = graph.Nodes[Prototype.StartNode];
var path = graph.Path(Prototype.StartNode, Prototype.TargetNode);
var edge = startNode.GetEdge(path[0].Name); if (!graph.TryPath(Prototype.StartNode, Prototype.TargetNode, out var path) ||
!startNode.TryGetEdge(path[0].Name, out var edge))
{
return;
}
edge.Steps[0].DoExamine(message, inDetailsRange); edge.Steps[0].DoExamine(message, inDetailsRange);
} }
} }

View File

@@ -20,6 +20,7 @@ using Robust.Shared.Localization;
using Robust.Shared.Log; using Robust.Shared.Log;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using DrawDepth = Content.Shared.GameObjects.DrawDepth; using DrawDepth = Content.Shared.GameObjects.DrawDepth;
namespace Content.Client.GameObjects.EntitySystems namespace Content.Client.GameObjects.EntitySystems
@@ -217,8 +218,11 @@ namespace Content.Client.GameObjects.EntitySystems
{ {
return false; return false;
} }
DebugTools.AssertNotNull(_dragger);
// still in range of the thing we are dragging? // still in range of the thing we are dragging?
if (!_interactionSystem.InRangeUnobstructed(_dragger, _dragDropHelper.Dragged)) if (!_interactionSystem.InRangeUnobstructed(_dragger!, _dragDropHelper.Dragged))
{ {
return false; return false;
} }

View File

@@ -66,7 +66,7 @@ namespace Content.Server.AI.Operators.Inventory
if (storageComponent.Open) if (storageComponent.Open)
{ {
var activateArgs = new ActivateEventArgs {User = _owner, Target = _target}; var activateArgs = new ActivateEventArgs(_owner, _target);
storageComponent.Activate(activateArgs); storageComponent.Activate(activateArgs);
} }

View File

@@ -43,7 +43,7 @@ namespace Content.Server.AI.Operators.Inventory
if (!storageComponent.Open) if (!storageComponent.Open)
{ {
var activateArgs = new ActivateEventArgs {User = _owner, Target = _target}; var activateArgs = new ActivateEventArgs(_owner, _target);
storageComponent.Activate(activateArgs); storageComponent.Activate(activateArgs);
} }

View File

@@ -239,7 +239,7 @@ namespace Content.Server.GameObjects.Components.Atmos
var activeHandEntity = handsComponent.GetActiveHand?.Owner; var activeHandEntity = handsComponent.GetActiveHand?.Owner;
if (activeHandEntity == null || !activeHandEntity.TryGetComponent(out GasAnalyzerComponent? gasAnalyzer)) if (activeHandEntity == null || !activeHandEntity.TryGetComponent(out GasAnalyzerComponent? gasAnalyzer))
{ {
serverMsg.Session.AttachedEntity.PopupMessage(Loc.GetString("You need a Gas Analyzer in your hand!")); serverMsg.Session.AttachedEntity?.PopupMessage(Loc.GetString("You need a Gas Analyzer in your hand!"));
return; return;
} }

View File

@@ -88,7 +88,7 @@ namespace Content.Server.GameObjects.Components.Body
} }
else // If surgery cannot be performed, show message saying so. else // If surgery cannot be performed, show message saying so.
{ {
eventArgs.Target.PopupMessage(eventArgs.User, eventArgs.Target?.PopupMessage(eventArgs.User,
Loc.GetString("You see no way to install the {0}.", Owner.Name)); Loc.GetString("You see no way to install the {0}.", Owner.Name));
} }
} }

View File

@@ -155,7 +155,7 @@ namespace Content.Server.GameObjects.Components.Body.Part
} }
else // If surgery cannot be performed, show message saying so. else // If surgery cannot be performed, show message saying so.
{ {
eventArgs.Target.PopupMessage(eventArgs.User, eventArgs.Target?.PopupMessage(eventArgs.User,
Loc.GetString("You see no way to install {0:theName}.", Owner)); Loc.GetString("You see no way to install {0:theName}.", Owner));
} }
} }

View File

@@ -16,8 +16,6 @@ using Robust.Server.Player;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Log; using Robust.Shared.Log;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
@@ -246,7 +244,9 @@ namespace Content.Server.GameObjects.Components.Body.Surgery
private void HandleReceiveMechanism(int key) private void HandleReceiveMechanism(int key)
{ {
// TODO: sanity checks to see whether user is in range, user is still able-bodied, target is still the same, etc etc // TODO: sanity checks to see whether user is in range, user is still able-bodied, target is still the same, etc etc
if (!_optionsCache.TryGetValue(key, out var targetObject) || if (BodyCache == null ||
!_optionsCache.TryGetValue(key, out var targetObject) ||
targetObject is not MechanismComponent target ||
PerformerCache == null || PerformerCache == null ||
!PerformerCache.TryGetComponent(out IActorComponent? actor)) !PerformerCache.TryGetComponent(out IActorComponent? actor))
{ {
@@ -254,20 +254,22 @@ namespace Content.Server.GameObjects.Components.Body.Surgery
return; return;
} }
var target = targetObject as MechanismComponent;
CloseSurgeryUI(actor.playerSession); CloseSurgeryUI(actor.playerSession);
_callbackCache?.Invoke(target, BodyCache, this, PerformerCache); _callbackCache?.Invoke(target, BodyCache, this, PerformerCache);
} }
private void NotUsefulPopup() private void NotUsefulPopup()
{ {
if (PerformerCache == null) return;
BodyCache?.Owner.PopupMessage(PerformerCache, BodyCache?.Owner.PopupMessage(PerformerCache,
Loc.GetString("You see no useful way to use {0:theName}.", Owner)); Loc.GetString("You see no useful way to use {0:theName}.", Owner));
} }
private void NotUsefulAnymorePopup() private void NotUsefulAnymorePopup()
{ {
if (PerformerCache == null) return;
BodyCache?.Owner.PopupMessage(PerformerCache, BodyCache?.Owner.PopupMessage(PerformerCache,
Loc.GetString("You see no useful way to use {0:theName} anymore.", Owner)); Loc.GetString("You see no useful way to use {0:theName} anymore.", Owner));
} }

View File

@@ -13,7 +13,6 @@ using Content.Shared.GameObjects.Components.Strap;
using Content.Shared.GameObjects.EntitySystems.ActionBlocker; using Content.Shared.GameObjects.EntitySystems.ActionBlocker;
using Content.Shared.GameObjects.Verbs; using Content.Shared.GameObjects.Verbs;
using Content.Shared.Interfaces; using Content.Shared.Interfaces;
using Content.Shared.Interfaces.GameObjects.Components;
using Content.Shared.Utility; using Content.Shared.Utility;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Shared.Containers; using Robust.Shared.Containers;
@@ -237,7 +236,7 @@ namespace Content.Server.GameObjects.Components.Buckle
public override bool TryBuckle(IEntity? user, IEntity to) public override bool TryBuckle(IEntity? user, IEntity to)
{ {
if (!CanBuckle(user, to, out var strap)) if (user == null || !CanBuckle(user, to, out var strap))
{ {
return false; return false;
} }

View File

@@ -15,8 +15,6 @@ using Robust.Shared.GameObjects;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Network; using Robust.Shared.Network;
using Robust.Shared.Players; using Robust.Shared.Players;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
@@ -201,11 +199,11 @@ namespace Content.Server.GameObjects.Components.Instruments
{ {
if (_laggedBatches == (int) (maxMidiLaggedBatches * (1 / 3d) + 1)) if (_laggedBatches == (int) (maxMidiLaggedBatches * (1 / 3d) + 1))
{ {
Owner.PopupMessage(InstrumentPlayer.AttachedEntity, InstrumentPlayer.AttachedEntity?.PopupMessage(
Loc.GetString("Your fingers are beginning to a cramp a little!")); Loc.GetString("Your fingers are beginning to a cramp a little!"));
} else if (_laggedBatches == (int) (maxMidiLaggedBatches * (2 / 3d) + 1)) } else if (_laggedBatches == (int) (maxMidiLaggedBatches * (2 / 3d) + 1))
{ {
Owner.PopupMessage(InstrumentPlayer.AttachedEntity, InstrumentPlayer.AttachedEntity?.PopupMessage(
Loc.GetString("Your fingers are seriously cramping up!")); Loc.GetString("Your fingers are seriously cramping up!"));
} }
} }
@@ -360,11 +358,11 @@ namespace Content.Server.GameObjects.Components.Instruments
stun.Stun(1); stun.Stun(1);
Clean(); Clean();
} }
Owner.PopupMessage(mob, "Your fingers cramp up from playing!");
} }
InstrumentPlayer = null; InstrumentPlayer = null;
Owner.PopupMessage(mob, "Your fingers cramp up from playing!");
} }
_timer += delta; _timer += delta;

View File

@@ -21,8 +21,6 @@ using Robust.Shared.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Players; using Robust.Shared.Players;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
@@ -139,20 +137,24 @@ namespace Content.Server.GameObjects.Components.Interactable
{ {
if (!WelderLit) if (!WelderLit)
{ {
if(!silent) Owner.PopupMessage(user, Loc.GetString("The welder is turned off!")); if (!silent && user != null)
Owner.PopupMessage(user, Loc.GetString("The welder is turned off!"));
return false; return false;
} }
if (!CanWeld(value)) if (!CanWeld(value))
{ {
if(!silent) Owner.PopupMessage(user, Loc.GetString("The welder does not have enough fuel for that!")); if (!silent && user != null)
Owner.PopupMessage(user, Loc.GetString("The welder does not have enough fuel for that!"));
return false; return false;
} }
if (_solutionComponent == null) if (_solutionComponent == null)
return false; return false;
bool succeeded = _solutionComponent.TryRemoveReagent("chem.WeldingFuel", ReagentUnit.New(value)); var succeeded = _solutionComponent.TryRemoveReagent("chem.WeldingFuel", ReagentUnit.New(value));
if (succeeded && !silent) if (succeeded && !silent)
{ {
@@ -192,7 +194,7 @@ namespace Content.Server.GameObjects.Components.Interactable
return true; return true;
} }
if (!CanLitWelder()) if (!CanLitWelder() && user != null)
{ {
Owner.PopupMessage(user, Loc.GetString("The welder has no fuel left!")); Owner.PopupMessage(user, Loc.GetString("The welder has no fuel left!"));
return false; return false;

View File

@@ -23,8 +23,6 @@ using Robust.Shared.Log;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Network; using Robust.Shared.Network;
using Robust.Shared.Players; using Robust.Shared.Players;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
@@ -481,7 +479,7 @@ namespace Content.Server.GameObjects.Components.Items.Storage
void IActivate.Activate(ActivateEventArgs eventArgs) void IActivate.Activate(ActivateEventArgs eventArgs)
{ {
((IUse) this).UseEntity(new UseEntityEventArgs { User = eventArgs.User }); ((IUse) this).UseEntity(new UseEntityEventArgs(eventArgs.User));
} }
/// <summary> /// <summary>

View File

@@ -15,13 +15,9 @@ namespace Content.Server.GameObjects.Components.Morgue
void IActivate.Activate(ActivateEventArgs eventArgs) void IActivate.Activate(ActivateEventArgs eventArgs)
{ {
if(Morgue != null && !Morgue.Deleted && Morgue.TryGetComponent<MorgueEntityStorageComponent>(out var comp)) if (Morgue != null && !Morgue.Deleted && Morgue.TryGetComponent<MorgueEntityStorageComponent>(out var comp))
{ {
comp.Activate(new ActivateEventArgs() comp.Activate(new ActivateEventArgs(eventArgs.User, Morgue));
{
User = eventArgs.User,
Target = Morgue
});
} }
} }
} }

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Items.Storage;
@@ -26,7 +25,6 @@ using Robust.Shared.IoC;
using Robust.Shared.Log; using Robust.Shared.Log;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Players; using Robust.Shared.Players;
namespace Content.Server.GameObjects.EntitySystems.Click namespace Content.Server.GameObjects.EntitySystems.Click
@@ -143,7 +141,7 @@ namespace Content.Server.GameObjects.EntitySystems.Click
} }
// all activates should only fire when in range / unbostructed // all activates should only fire when in range / unbostructed
var activateEventArgs = new ActivateEventArgs { User = user, Target = used }; var activateEventArgs = new ActivateEventArgs(user, used);
if (activateEventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true)) if (activateEventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true))
{ {
activateComp.Activate(activateEventArgs); activateComp.Activate(activateEventArgs);
@@ -432,10 +430,7 @@ namespace Content.Server.GameObjects.EntitySystems.Click
return; return;
var attackBys = attacked.GetAllComponents<IInteractUsing>().OrderByDescending(x => x.Priority); var attackBys = attacked.GetAllComponents<IInteractUsing>().OrderByDescending(x => x.Priority);
var attackByEventArgs = new InteractUsingEventArgs var attackByEventArgs = new InteractUsingEventArgs(user, clickLocation, weapon, attacked);
{
User = user, ClickLocation = clickLocation, Using = weapon, Target = attacked
};
// all AttackBys should only happen when in range / unobstructed, so no range check is needed // all AttackBys should only happen when in range / unobstructed, so no range check is needed
if (attackByEventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true)) if (attackByEventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true))
@@ -474,7 +469,7 @@ namespace Content.Server.GameObjects.EntitySystems.Click
if (message.Handled) if (message.Handled)
return; return;
var attackHandEventArgs = new InteractHandEventArgs { User = user, Target = attacked }; var attackHandEventArgs = new InteractHandEventArgs(user, attacked);
// all attackHands should only fire when in range / unobstructed // all attackHands should only fire when in range / unobstructed
if (attackHandEventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true)) if (attackHandEventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true))
@@ -534,7 +529,7 @@ namespace Content.Server.GameObjects.EntitySystems.Click
// Try to use item on any components which have the interface // Try to use item on any components which have the interface
foreach (var use in uses) foreach (var use in uses)
{ {
if (use.UseEntity(new UseEntityEventArgs { User = user })) if (use.UseEntity(new UseEntityEventArgs(user)))
{ {
// If a Use returns a status completion we finish our attack // If a Use returns a status completion we finish our attack
return; return;
@@ -753,10 +748,7 @@ namespace Content.Server.GameObjects.EntitySystems.Click
return; return;
var rangedAttackBys = attacked.GetAllComponents<IRangedInteract>().ToList(); var rangedAttackBys = attacked.GetAllComponents<IRangedInteract>().ToList();
var rangedAttackByEventArgs = new RangedInteractEventArgs var rangedAttackByEventArgs = new RangedInteractEventArgs(user, weapon, clickLocation);
{
User = user, Using = weapon, ClickLocation = clickLocation
};
// See if we have a ranged attack interaction // See if we have a ranged attack interaction
foreach (var t in rangedAttackBys) foreach (var t in rangedAttackBys)

View File

@@ -352,11 +352,18 @@ namespace Content.Server.GameObjects.EntitySystems
return; return;
} }
var user = args.SenderSession.AttachedEntity;
if (user == null)
{
Logger.Error($"Client sent {nameof(TryStartStructureConstructionMessage)} with no attached entity!");
return;
}
var startNode = constructionGraph.Nodes[constructionPrototype.StartNode]; var startNode = constructionGraph.Nodes[constructionPrototype.StartNode];
var targetNode = constructionGraph.Nodes[constructionPrototype.TargetNode]; var targetNode = constructionGraph.Nodes[constructionPrototype.TargetNode];
var pathFind = constructionGraph.Path(startNode.Name, targetNode.Name); var pathFind = constructionGraph.Path(startNode.Name, targetNode.Name);
var user = args.SenderSession.AttachedEntity;
if (_beingBuilt.TryGetValue(args.SenderSession, out var set)) if (_beingBuilt.TryGetValue(args.SenderSession, out var set))
{ {

View File

@@ -69,7 +69,7 @@ namespace Content.Server.GameObjects.EntitySystems
? viewerPointedAtMessage ? viewerPointedAtMessage
: viewerMessage; : viewerMessage;
source.PopupMessage(viewer.AttachedEntity, message); source.PopupMessage(viewerEntity, message);
} }
} }

View File

@@ -1,6 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Robust.Shared.Prototypes; using System.Diagnostics.CodeAnalysis;
using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
@@ -12,12 +12,13 @@ namespace Content.Shared.Construction
{ {
[DataField("actions", serverOnly: true)] [DataField("actions", serverOnly: true)]
private List<IGraphAction> _actions = new(); private List<IGraphAction> _actions = new();
[DataField("edges")] [DataField("edges")]
private List<ConstructionGraphEdge> _edges = new(); private List<ConstructionGraphEdge> _edges = new();
[ViewVariables] [ViewVariables]
[DataField("node")] [DataField("node", required: true)]
public string Name { get; private set; } public string Name { get; private set; } = default!;
[ViewVariables] [ViewVariables]
public IReadOnlyList<ConstructionGraphEdge> Edges => _edges; public IReadOnlyList<ConstructionGraphEdge> Edges => _edges;
@@ -27,9 +28,9 @@ namespace Content.Shared.Construction
[ViewVariables] [ViewVariables]
[DataField("entity")] [DataField("entity")]
public string Entity { get; private set; } public string? Entity { get; private set; }
public ConstructionGraphEdge GetEdge(string target) public ConstructionGraphEdge? GetEdge(string target)
{ {
foreach (var edge in _edges) foreach (var edge in _edges)
{ {
@@ -39,5 +40,10 @@ namespace Content.Shared.Construction
return null; return null;
} }
public bool TryGetEdge(string target, [NotNullWhen(true)] out ConstructionGraphEdge? edge)
{
return (edge = GetEdge(target)) != null;
}
} }
} }

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
@@ -12,8 +13,8 @@ namespace Content.Shared.Construction
public class ConstructionGraphPrototype : IPrototype, ISerializationHooks public class ConstructionGraphPrototype : IPrototype, ISerializationHooks
{ {
private readonly Dictionary<string, ConstructionGraphNode> _nodes = new(); private readonly Dictionary<string, ConstructionGraphNode> _nodes = new();
private readonly Dictionary<ValueTuple<string, string>, ConstructionGraphNode[]> _paths = new(); private readonly Dictionary<ValueTuple<string, string>, ConstructionGraphNode[]?> _paths = new();
private readonly Dictionary<string, Dictionary<ConstructionGraphNode, ConstructionGraphNode>> _pathfinding = new(); private readonly Dictionary<string, Dictionary<ConstructionGraphNode, ConstructionGraphNode?>> _pathfinding = new();
[ViewVariables] [ViewVariables]
[field: DataField("id", required: true)] [field: DataField("id", required: true)]
@@ -21,7 +22,7 @@ namespace Content.Shared.Construction
[ViewVariables] [ViewVariables]
[field: DataField("start")] [field: DataField("start")]
public string Start { get; } public string? Start { get; }
[DataField("graph", priority: 0)] [DataField("graph", priority: 0)]
private List<ConstructionGraphNode> _graph = new(); private List<ConstructionGraphNode> _graph = new();
@@ -35,20 +36,30 @@ namespace Content.Shared.Construction
foreach (var graphNode in _graph) foreach (var graphNode in _graph)
{ {
if (string.IsNullOrEmpty(graphNode.Name))
{
throw new InvalidDataException($"Name of graph node is null in construction graph {ID}!");
}
_nodes[graphNode.Name] = graphNode; _nodes[graphNode.Name] = graphNode;
} }
if(string.IsNullOrEmpty(Start) || !_nodes.ContainsKey(Start)) if (string.IsNullOrEmpty(Start) || !_nodes.ContainsKey(Start))
throw new InvalidDataException($"Starting node for construction graph {ID} is null, empty or invalid!"); throw new InvalidDataException($"Starting node for construction graph {ID} is null, empty or invalid!");
} }
public ConstructionGraphEdge Edge(string startNode, string nextNode) public ConstructionGraphEdge? Edge(string startNode, string nextNode)
{ {
var start = _nodes[startNode]; var start = _nodes[startNode];
return start.GetEdge(nextNode); return start.GetEdge(nextNode);
} }
public ConstructionGraphNode[] Path(string startNode, string finishNode) public bool TryPath(string startNode, string finishNode, [NotNullWhen(true)] out ConstructionGraphNode[]? path)
{
return (path = Path(startNode, finishNode)) != null;
}
public ConstructionGraphNode[]? Path(string startNode, string finishNode)
{ {
var tuple = new ValueTuple<string, string>(startNode, finishNode); var tuple = new ValueTuple<string, string>(startNode, finishNode);
@@ -57,7 +68,7 @@ namespace Content.Shared.Construction
// Get graph given the current start. // Get graph given the current start.
Dictionary<ConstructionGraphNode, ConstructionGraphNode> pathfindingForStart; Dictionary<ConstructionGraphNode, ConstructionGraphNode?> pathfindingForStart;
if (_pathfinding.ContainsKey(startNode)) if (_pathfinding.ContainsKey(startNode))
{ {
pathfindingForStart = _pathfinding[startNode]; pathfindingForStart = _pathfinding[startNode];
@@ -76,8 +87,6 @@ namespace Content.Shared.Construction
var path = new List<ConstructionGraphNode>(); var path = new List<ConstructionGraphNode>();
while (current != start) while (current != start)
{ {
path.Add(current);
// No path. // No path.
if (current == null || !pathfindingForStart.ContainsKey(current)) if (current == null || !pathfindingForStart.ContainsKey(current))
{ {
@@ -86,6 +95,8 @@ namespace Content.Shared.Construction
return null; return null;
} }
path.Add(current);
current = pathfindingForStart[current]; current = pathfindingForStart[current];
} }
@@ -97,13 +108,13 @@ namespace Content.Shared.Construction
/// Uses breadth first search for pathfinding. /// Uses breadth first search for pathfinding.
/// </summary> /// </summary>
/// <param name="start"></param> /// <param name="start"></param>
private Dictionary<ConstructionGraphNode, ConstructionGraphNode> PathsForStart(string start) private Dictionary<ConstructionGraphNode, ConstructionGraphNode?> PathsForStart(string start)
{ {
// TODO: Make this use A* or something, although it's not that important. // TODO: Make this use A* or something, although it's not that important.
var startNode = _nodes[start]; var startNode = _nodes[start];
var frontier = new Queue<ConstructionGraphNode>(); var frontier = new Queue<ConstructionGraphNode>();
var cameFrom = new Dictionary<ConstructionGraphNode, ConstructionGraphNode>(); var cameFrom = new Dictionary<ConstructionGraphNode, ConstructionGraphNode?>();
frontier.Enqueue(startNode); frontier.Enqueue(startNode);
cameFrom[startNode] = null; cameFrom[startNode] = null;

View File

@@ -10,6 +10,7 @@
<Configurations>Release;Debug</Configurations> <Configurations>Release;Debug</Configurations>
<Platforms>AnyCPU</Platforms> <Platforms>AnyCPU</Platforms>
<WarningsAsErrors>nullable</WarningsAsErrors> <WarningsAsErrors>nullable</WarningsAsErrors>
<Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<Import Project="..\RobustToolbox\MSBuild\Robust.DefineConstants.targets" /> <Import Project="..\RobustToolbox\MSBuild\Robust.DefineConstants.targets" />
<ItemGroup> <ItemGroup>

View File

@@ -1,11 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Shared.GameObjects.Components.Movement; using Content.Shared.GameObjects.Components.Movement;
using Content.Shared.GameObjects.EntitySystems.EffectBlocker;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Reflection; using Robust.Shared.Reflection;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Utility; using Robust.Shared.Utility;
@@ -16,16 +14,14 @@ namespace Content.Shared.GameObjects.Components.Inventory
{ {
public abstract class SharedInventoryComponent : Component, IMoveSpeedModifier public abstract class SharedInventoryComponent : Component, IMoveSpeedModifier
{ {
// ReSharper disable UnassignedReadonlyField [Dependency] protected readonly IReflectionManager ReflectionManager = default!;
[Dependency] protected readonly IReflectionManager ReflectionManager; [Dependency] protected readonly IDynamicTypeFactory DynamicTypeFactory = default!;
[Dependency] protected readonly IDynamicTypeFactory DynamicTypeFactory;
// ReSharper restore UnassignedReadonlyField
public sealed override string Name => "Inventory"; public sealed override string Name => "Inventory";
public sealed override uint? NetID => ContentNetIDs.STORAGE; public sealed override uint? NetID => ContentNetIDs.STORAGE;
[ViewVariables] [ViewVariables]
protected Inventory InventoryInstance { get; private set; } protected Inventory InventoryInstance { get; private set; } = default!;
[ViewVariables] [ViewVariables]
[DataField("Template")] [DataField("Template")]
@@ -42,7 +38,7 @@ namespace Content.Shared.GameObjects.Components.Inventory
{ {
var type = ReflectionManager.LooseGetType(_templateName); var type = ReflectionManager.LooseGetType(_templateName);
DebugTools.Assert(type != null); DebugTools.Assert(type != null);
InventoryInstance = DynamicTypeFactory.CreateInstance<Inventory>(type); InventoryInstance = DynamicTypeFactory.CreateInstance<Inventory>(type!);
} }
/// <returns>true if the item is equipped to an equip slot (NOT inside an equipped container /// <returns>true if the item is equipped to an equip slot (NOT inside an equipped container

View File

@@ -40,13 +40,13 @@ namespace Content.Shared.GameObjects.Components.Materials
[DataDefinition] [DataDefinition]
public class MaterialDataEntry : ISerializationHooks public class MaterialDataEntry : ISerializationHooks
{ {
public object Key; public object Key = default!;
[DataField("key")] [DataField("key", required: true)]
public string StringKey; public string StringKey = default!;
[DataField("mat")] [DataField("mat", required: true)]
public string Value; public string Value = default!;
void ISerializationHooks.AfterDeserialization() void ISerializationHooks.AfterDeserialization()
{ {

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
@@ -22,10 +21,10 @@ namespace Content.Shared.GameObjects.Components
{ {
public float Pressure; public float Pressure;
public float Temperature; public float Temperature;
public GasEntry[] Gases; public GasEntry[]? Gases;
public string Error = string.Empty; public string? Error;
public GasAnalyzerBoundUserInterfaceState(float pressure, float temperature, GasEntry[] gases, string error = null) public GasAnalyzerBoundUserInterfaceState(float pressure, float temperature, GasEntry[]? gases, string? error = null)
{ {
Pressure = pressure; Pressure = pressure;
Temperature = temperature; Temperature = temperature;

View File

@@ -76,7 +76,7 @@ namespace Content.Shared.GameObjects.Components
return new StackComponentState(Count, MaxCount); return new StackComponentState(Count, MaxCount);
} }
public override void HandleComponentState(ComponentState curState, ComponentState nextState) public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
{ {
if (curState is not StackComponentState cast) if (curState is not StackComponentState cast)
{ {

View File

@@ -4,10 +4,8 @@ using Content.Shared.Interfaces.GameObjects.Components;
using Content.Shared.Physics; using Content.Shared.Physics;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Physics; using Robust.Shared.Physics;
using Robust.Shared.Physics.Broadphase; using Robust.Shared.Physics.Broadphase;
@@ -40,7 +38,7 @@ namespace Content.Shared.GameObjects.EntitySystems
MapCoordinates origin, MapCoordinates origin,
MapCoordinates other, MapCoordinates other,
int collisionMask = (int) CollisionGroup.Impassable, int collisionMask = (int) CollisionGroup.Impassable,
Ignored predicate = null) Ignored? predicate = null)
{ {
var dir = other.Position - origin.Position; var dir = other.Position - origin.Position;
@@ -69,7 +67,7 @@ namespace Content.Shared.GameObjects.EntitySystems
MapCoordinates origin, MapCoordinates origin,
MapCoordinates other, MapCoordinates other,
int collisionMask = (int) CollisionGroup.Impassable, int collisionMask = (int) CollisionGroup.Impassable,
IEntity ignoredEnt = null) IEntity? ignoredEnt = null)
{ {
var predicate = ignoredEnt == null var predicate = ignoredEnt == null
? null ? null
@@ -111,7 +109,7 @@ namespace Content.Shared.GameObjects.EntitySystems
MapCoordinates other, MapCoordinates other,
float range = InteractionRange, float range = InteractionRange,
CollisionGroup collisionMask = CollisionGroup.Impassable, CollisionGroup collisionMask = CollisionGroup.Impassable,
Ignored predicate = null, Ignored? predicate = null,
bool ignoreInsideBlocker = false) bool ignoreInsideBlocker = false)
{ {
if (!origin.InRange(other, range)) return false; if (!origin.InRange(other, range)) return false;
@@ -132,7 +130,7 @@ namespace Content.Shared.GameObjects.EntitySystems
foreach (var result in rayResults) foreach (var result in rayResults)
{ {
if (!result.HitEntity.TryGetComponent(out IPhysBody p)) if (!result.HitEntity.TryGetComponent(out IPhysBody? p))
{ {
continue; continue;
} }
@@ -186,7 +184,7 @@ namespace Content.Shared.GameObjects.EntitySystems
IEntity other, IEntity other,
float range = InteractionRange, float range = InteractionRange,
CollisionGroup collisionMask = CollisionGroup.Impassable, CollisionGroup collisionMask = CollisionGroup.Impassable,
Ignored predicate = null, Ignored? predicate = null,
bool ignoreInsideBlocker = false, bool ignoreInsideBlocker = false,
bool popup = false) bool popup = false)
{ {
@@ -242,7 +240,7 @@ namespace Content.Shared.GameObjects.EntitySystems
IComponent other, IComponent other,
float range = InteractionRange, float range = InteractionRange,
CollisionGroup collisionMask = CollisionGroup.Impassable, CollisionGroup collisionMask = CollisionGroup.Impassable,
Ignored predicate = null, Ignored? predicate = null,
bool ignoreInsideBlocker = false, bool ignoreInsideBlocker = false,
bool popup = false) bool popup = false)
{ {
@@ -298,7 +296,7 @@ namespace Content.Shared.GameObjects.EntitySystems
EntityCoordinates other, EntityCoordinates other,
float range = InteractionRange, float range = InteractionRange,
CollisionGroup collisionMask = CollisionGroup.Impassable, CollisionGroup collisionMask = CollisionGroup.Impassable,
Ignored predicate = null, Ignored? predicate = null,
bool ignoreInsideBlocker = false, bool ignoreInsideBlocker = false,
bool popup = false) bool popup = false)
{ {
@@ -354,7 +352,7 @@ namespace Content.Shared.GameObjects.EntitySystems
MapCoordinates other, MapCoordinates other,
float range = InteractionRange, float range = InteractionRange,
CollisionGroup collisionMask = CollisionGroup.Impassable, CollisionGroup collisionMask = CollisionGroup.Impassable,
Ignored predicate = null, Ignored? predicate = null,
bool ignoreInsideBlocker = false, bool ignoreInsideBlocker = false,
bool popup = false) bool popup = false)
{ {
@@ -408,7 +406,7 @@ namespace Content.Shared.GameObjects.EntitySystems
ITargetedInteractEventArgs args, ITargetedInteractEventArgs args,
float range = InteractionRange, float range = InteractionRange,
CollisionGroup collisionMask = CollisionGroup.Impassable, CollisionGroup collisionMask = CollisionGroup.Impassable,
Ignored predicate = null, Ignored? predicate = null,
bool ignoreInsideBlocker = false, bool ignoreInsideBlocker = false,
bool popup = false) bool popup = false)
{ {
@@ -453,7 +451,7 @@ namespace Content.Shared.GameObjects.EntitySystems
DragDropEventArgs args, DragDropEventArgs args,
float range = InteractionRange, float range = InteractionRange,
CollisionGroup collisionMask = CollisionGroup.Impassable, CollisionGroup collisionMask = CollisionGroup.Impassable,
Ignored predicate = null, Ignored? predicate = null,
bool ignoreInsideBlocker = false, bool ignoreInsideBlocker = false,
bool popup = false) bool popup = false)
{ {
@@ -521,7 +519,7 @@ namespace Content.Shared.GameObjects.EntitySystems
AfterInteractEventArgs args, AfterInteractEventArgs args,
float range = InteractionRange, float range = InteractionRange,
CollisionGroup collisionMask = CollisionGroup.Impassable, CollisionGroup collisionMask = CollisionGroup.Impassable,
Ignored predicate = null, Ignored? predicate = null,
bool ignoreInsideBlocker = false, bool ignoreInsideBlocker = false,
bool popup = false) bool popup = false)
{ {

View File

@@ -23,8 +23,14 @@ namespace Content.Shared.Interfaces.GameObjects.Components
public class ActivateEventArgs : EventArgs, ITargetedInteractEventArgs public class ActivateEventArgs : EventArgs, ITargetedInteractEventArgs
{ {
public IEntity User { get; set; } public ActivateEventArgs(IEntity user, IEntity target)
public IEntity Target { get; set; } {
User = user;
Target = target;
}
public IEntity User { get; }
public IEntity Target { get; }
} }
/// <summary> /// <summary>

View File

@@ -20,8 +20,14 @@ namespace Content.Shared.Interfaces.GameObjects.Components
public class InteractHandEventArgs : EventArgs, ITargetedInteractEventArgs public class InteractHandEventArgs : EventArgs, ITargetedInteractEventArgs
{ {
public IEntity User { get; set; } public InteractHandEventArgs(IEntity user, IEntity target)
public IEntity Target { get; set; } {
User = user;
Target = target;
}
public IEntity User { get; }
public IEntity Target { get; }
} }

View File

@@ -29,10 +29,18 @@ namespace Content.Shared.Interfaces.GameObjects.Components
public class InteractUsingEventArgs : EventArgs, ITargetedInteractEventArgs public class InteractUsingEventArgs : EventArgs, ITargetedInteractEventArgs
{ {
public IEntity User { get; set; } public InteractUsingEventArgs(IEntity user, EntityCoordinates clickLocation, IEntity @using, IEntity target)
public EntityCoordinates ClickLocation { get; set; } {
public IEntity Using { get; set; } User = user;
public IEntity Target { get; set; } ClickLocation = clickLocation;
Using = @using;
Target = target;
}
public IEntity User { get; }
public EntityCoordinates ClickLocation { get; }
public IEntity Using { get; }
public IEntity Target { get; }
} }
/// <summary> /// <summary>

View File

@@ -23,9 +23,16 @@ namespace Content.Shared.Interfaces.GameObjects.Components
[PublicAPI] [PublicAPI]
public class RangedInteractEventArgs : EventArgs public class RangedInteractEventArgs : EventArgs
{ {
public IEntity User { get; set; } public RangedInteractEventArgs(IEntity user, IEntity @using, EntityCoordinates clickLocation)
public IEntity Using { get; set; } {
public EntityCoordinates ClickLocation { get; set; } User = user;
Using = @using;
ClickLocation = clickLocation;
}
public IEntity User { get; }
public IEntity Using { get; }
public EntityCoordinates ClickLocation { get; }
} }
/// <summary> /// <summary>

View File

@@ -21,7 +21,12 @@ namespace Content.Shared.Interfaces.GameObjects.Components
public class UseEntityEventArgs : EventArgs public class UseEntityEventArgs : EventArgs
{ {
public IEntity User { get; set; } public UseEntityEventArgs(IEntity user)
{
User = user;
}
public IEntity User { get; }
} }
/// <summary> /// <summary>