* Implement device networking * Implement device configuration menu * Fix device network * Implement disposal mailing unit * Implement base network connection Implement wired and wireless network connection Implement device network metadata * Fix dereference null error * Fix wired network null checks * Change BaseNetworks enum to NetworkUtils class Add PingResponse function to NetworkUtils Change device network file structure * Add doc comments * Apply suggestions from code review Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com> * Add tag validation to disposal mailing unit * Add tag validation to the mailing unit component * Address reviews Change WiredNetwork can connect check Change device networking string literals to constants * Address reviews Revert changes to PowerProvider and PowerReceiver Add new NodeGroup WELP * Fix recursive access to Owner property * Integrate suggested changes * Fix TryGetWireNet acting on NullPowerProvider Fix network connections not checking if their owner has been deleted * Close device network connection when the owning entity got deleted Fix mailing unit not closing the device network connection on remove * Remove GetWireNet from NullPowerProvider Co-authored-by: Julian Giebel <j.giebel@netrocks.info> Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com>
250 lines
8.2 KiB
C#
250 lines
8.2 KiB
C#
#nullable enable
|
|
using System;
|
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
|
using Content.Shared.GameObjects.Components.Power;
|
|
using Content.Shared.GameObjects.EntitySystems;
|
|
using Robust.Server.GameObjects;
|
|
using Robust.Server.Interfaces.GameObjects;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.GameObjects.ComponentDependencies;
|
|
using Robust.Shared.GameObjects.Components;
|
|
using Robust.Shared.IoC;
|
|
using Robust.Shared.Localization;
|
|
using Robust.Shared.Serialization;
|
|
using Robust.Shared.Utility;
|
|
using Robust.Shared.ViewVariables;
|
|
|
|
namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
|
|
{
|
|
/// <summary>
|
|
/// Attempts to link with a nearby <see cref="IPowerProvider"/>s so that it can receive power from a <see cref="IApcNet"/>.
|
|
/// </summary>
|
|
[RegisterComponent]
|
|
public class PowerReceiverComponent : Component, IExamine
|
|
{
|
|
[Dependency] private readonly IServerEntityManager _serverEntityManager = default!;
|
|
|
|
[ViewVariables] [ComponentDependency] private readonly IPhysicsComponent? _physicsComponent = null;
|
|
|
|
public override string Name => "PowerReceiver";
|
|
|
|
public event EventHandler<PowerStateEventArgs>? OnPowerStateChanged;
|
|
|
|
[ViewVariables]
|
|
public bool Powered => (HasApcPower || !NeedsPower) && !PowerDisabled;
|
|
|
|
[ViewVariables]
|
|
public bool HasApcPower { get => _hasApcPower; set => SetHasApcPower(value); }
|
|
private bool _hasApcPower;
|
|
|
|
/// <summary>
|
|
/// The max distance from a <see cref="PowerProviderComponent"/> that this can receive power from.
|
|
/// </summary>
|
|
[ViewVariables(VVAccess.ReadWrite)]
|
|
public int PowerReceptionRange { get => _powerReceptionRange; set => SetPowerReceptionRange(value); }
|
|
private int _powerReceptionRange;
|
|
|
|
[ViewVariables]
|
|
public IPowerProvider Provider { get => _provider; set => SetProvider(value); }
|
|
private IPowerProvider _provider = PowerProviderComponent.NullProvider;
|
|
|
|
/// <summary>
|
|
/// If this should be considered for connection by <see cref="PowerProviderComponent"/>s.
|
|
/// </summary>
|
|
public bool Connectable => Anchored;
|
|
|
|
private bool Anchored => _physicsComponent == null || _physicsComponent.Anchored;
|
|
|
|
[ViewVariables]
|
|
public bool NeedsProvider { get; private set; } = true;
|
|
|
|
/// <summary>
|
|
/// Amount of charge this needs from an APC per second to function.
|
|
/// </summary>
|
|
[ViewVariables(VVAccess.ReadWrite)]
|
|
public int Load { get => _load; set => SetLoad(value); }
|
|
private int _load;
|
|
|
|
/// <summary>
|
|
/// When false, causes this to appear powered even if not receiving power from an Apc.
|
|
/// </summary>
|
|
[ViewVariables(VVAccess.ReadWrite)]
|
|
public bool NeedsPower { get => _needsPower; set => SetNeedsPower(value); }
|
|
private bool _needsPower;
|
|
|
|
/// <summary>
|
|
/// When true, causes this to never appear powered.
|
|
/// </summary>
|
|
[ViewVariables(VVAccess.ReadWrite)]
|
|
public bool PowerDisabled { get => _powerDisabled; set => SetPowerDisabled(value); }
|
|
private bool _powerDisabled;
|
|
|
|
public override void ExposeData(ObjectSerializer serializer)
|
|
{
|
|
base.ExposeData(serializer);
|
|
serializer.DataField(ref _powerReceptionRange, "powerReceptionRange", 3);
|
|
serializer.DataField(ref _load, "powerLoad", 5);
|
|
serializer.DataField(ref _needsPower, "needsPower", true);
|
|
serializer.DataField(ref _powerDisabled, "powerDisabled", false);
|
|
}
|
|
|
|
protected override void Startup()
|
|
{
|
|
base.Startup();
|
|
if (NeedsProvider)
|
|
{
|
|
TryFindAndSetProvider();
|
|
}
|
|
if (_physicsComponent != null)
|
|
{
|
|
AnchorUpdate();
|
|
_physicsComponent.AnchoredChanged += AnchorUpdate;
|
|
}
|
|
}
|
|
|
|
public override void OnRemove()
|
|
{
|
|
if (_physicsComponent != null)
|
|
{
|
|
_physicsComponent.AnchoredChanged -= AnchorUpdate;
|
|
}
|
|
_provider.RemoveReceiver(this);
|
|
base.OnRemove();
|
|
}
|
|
|
|
public void TryFindAndSetProvider()
|
|
{
|
|
if (TryFindAvailableProvider(out var provider))
|
|
{
|
|
Provider = provider;
|
|
}
|
|
}
|
|
|
|
private bool TryFindAvailableProvider(out IPowerProvider foundProvider)
|
|
{
|
|
var nearbyEntities = _serverEntityManager
|
|
.GetEntitiesInRange(Owner, PowerReceptionRange);
|
|
|
|
foreach (var entity in nearbyEntities)
|
|
{
|
|
if (entity.TryGetComponent<PowerProviderComponent>(out var provider))
|
|
{
|
|
if (provider.Connectable)
|
|
{
|
|
if (provider.Owner.Transform.Coordinates.TryDistance(_serverEntityManager, Owner.Transform.Coordinates, out var distance))
|
|
{
|
|
if (distance < Math.Min(PowerReceptionRange, provider.PowerTransferRange))
|
|
{
|
|
foundProvider = provider;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
foundProvider = default!;
|
|
return false;
|
|
}
|
|
|
|
public void ClearProvider()
|
|
{
|
|
_provider.RemoveReceiver(this);
|
|
_provider = PowerProviderComponent.NullProvider;
|
|
NeedsProvider = true;
|
|
HasApcPower = false;
|
|
}
|
|
|
|
private void SetProvider(IPowerProvider newProvider)
|
|
{
|
|
_provider.RemoveReceiver(this);
|
|
_provider = newProvider;
|
|
newProvider.AddReceiver(this);
|
|
NeedsProvider = false;
|
|
}
|
|
|
|
private void SetHasApcPower(bool newHasApcPower)
|
|
{
|
|
var oldPowered = Powered;
|
|
_hasApcPower = newHasApcPower;
|
|
if (oldPowered != Powered)
|
|
{
|
|
OnNewPowerState();
|
|
}
|
|
}
|
|
|
|
private void SetPowerReceptionRange(int newPowerReceptionRange)
|
|
{
|
|
ClearProvider();
|
|
_powerReceptionRange = newPowerReceptionRange;
|
|
TryFindAndSetProvider();
|
|
}
|
|
|
|
private void SetLoad(int newLoad)
|
|
{
|
|
_load = newLoad;
|
|
}
|
|
|
|
private void SetNeedsPower(bool newNeedsPower)
|
|
{
|
|
var oldPowered = Powered;
|
|
_needsPower = newNeedsPower;
|
|
if (oldPowered != Powered)
|
|
{
|
|
OnNewPowerState();
|
|
}
|
|
}
|
|
|
|
private void SetPowerDisabled(bool newPowerDisabled)
|
|
{
|
|
var oldPowered = Powered;
|
|
_powerDisabled = newPowerDisabled;
|
|
if (oldPowered != Powered)
|
|
{
|
|
OnNewPowerState();
|
|
}
|
|
}
|
|
|
|
private void OnNewPowerState()
|
|
{
|
|
OnPowerStateChanged?.Invoke(this, new PowerStateEventArgs(Powered));
|
|
if (Owner.TryGetComponent<AppearanceComponent>(out var appearance))
|
|
{
|
|
appearance.SetData(PowerDeviceVisuals.Powered, Powered);
|
|
}
|
|
}
|
|
|
|
private void AnchorUpdate()
|
|
{
|
|
if (Anchored)
|
|
{
|
|
if (NeedsProvider)
|
|
{
|
|
TryFindAndSetProvider();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ClearProvider();
|
|
}
|
|
}
|
|
///<summary>
|
|
///Adds some markup to the examine text of whatever object is using this component to tell you if it's powered or not, even if it doesn't have an icon state to do this for you.
|
|
///</summary>
|
|
|
|
public void Examine(FormattedMessage message, bool inDetailsRange)
|
|
{
|
|
message.AddMarkup(Loc.GetString("It appears to be {0}.", Powered ? "[color=darkgreen]powered[/color]" : "[color=darkred]un-powered[/color]"));
|
|
}
|
|
}
|
|
|
|
public class PowerStateEventArgs : EventArgs
|
|
{
|
|
public readonly bool Powered;
|
|
|
|
public PowerStateEventArgs(bool powered)
|
|
{
|
|
Powered = powered;
|
|
}
|
|
}
|
|
}
|