Files
tbd-station-14/Content.Server/GameObjects/Components/Power/PowerTransferComponent.cs
Tyler Young ef751f68dc Faster Power (#596)
uses SnapGridComponent to select nearby wires instead of entity list (only marginally faster if entity queries are using DynamicTree)

TheoreticalLoad double dipping property setter, reduced to one update

minor refactoring

Co-authored-by: Tyler Young <tyler.young@impromptu.ninja>
2020-02-06 14:50:52 +01:00

157 lines
5.1 KiB
C#

using System.Linq;
using Content.Server.GameObjects.Components.Interactable.Tools;
using Content.Server.GameObjects.Components.Stack;
using Content.Server.GameObjects.EntitySystems;
using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.Transform;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.GameObjects.Components;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Power
{
/// <summary>
/// Component to transfer power to nearby components, can create powernets and connect to nodes
/// </summary>
[RegisterComponent]
public class PowerTransferComponent : Component, IAttackBy
{
public override string Name => "PowerTransfer";
/// <summary>
/// The powernet this component is connected to
/// </summary>
[ViewVariables]
public Powernet Parent { get; set; }
[ViewVariables]
public bool Regenerating { get; set; } = false;
protected override void Startup()
{
base.Startup();
if (Parent == null)
{
SpreadPowernet();
}
}
public override void OnRemove()
{
DisconnectFromPowernet();
base.OnRemove();
}
/// <summary>
/// Searches for local powernets to connect to, otherwise creates its own, and spreads powernet to nearby entities
/// </summary>
public void SpreadPowernet()
{
var entMgr = IoCManager.Resolve<IServerEntityManager>();
var sgc = Owner.GetComponent<SnapGridComponent>();
var wires = sgc.GetCardinalNeighborCells()
.SelectMany(x => x.GetLocal()).Distinct()
.Select(x => x.TryGetComponent<PowerTransferComponent>(out var c) ? c : null)
.Where(x => x != null).Distinct()
.ToArray();
//we have no parent so lets find a partner we can join his powernet
if (Parent == null || Regenerating)
{
foreach (var wire in wires)
{
if (wire.CanConnectTo())
{
ConnectToPowernet(wire.Parent);
break;
}
}
//we couldn't find a partner so none must have spread yet, lets make our own powernet to spread
if (Parent == null || Regenerating)
{
ConnectToPowernet(new Powernet());
}
}
//Find nodes intersecting us and if not already assigned to a powernet assign them to us
var nodes = entMgr.GetEntitiesIntersecting(Owner)
.Select(x => x.TryGetComponent(out PowerNodeComponent pnc) ? pnc : null)
.Where(x => x != null);
foreach (var node in nodes)
{
if (node.Parent == null)
{
node.ConnectToPowernet(Parent);
}
else if (node.Parent.Dirty)
{
node.RegeneratePowernet(Parent);
}
}
//spread powernet to nearby wires which haven't got one yet, and tell them to spread as well
foreach (var wire in wires)
{
if (wire.Parent == null || Regenerating)
{
wire.ConnectToPowernet(Parent);
wire.SpreadPowernet();
}
else if (wire.Parent != Parent && !wire.Parent.Dirty)
{
Parent.MergePowernets(wire.Parent);
}
}
}
/// <summary>
/// Called when connecting to a new powernet, either on creation or on regeneration
/// </summary>
/// <param name="toconnect"></param>
public void ConnectToPowernet(Powernet toconnect)
{
Parent = toconnect;
Parent.WireList.Add(this);
Regenerating = false;
}
/// <summary>
/// Called when we are removed and telling the powernet that it is now dirty and must regenerate
/// </summary>
public void DisconnectFromPowernet()
{
Parent.WireList.Remove(this);
Parent.Dirty = true;
Parent = null;
}
public bool CanConnectTo()
{
return Parent != null && Parent.Dirty == false && !Regenerating;
}
public bool AttackBy(AttackByEventArgs eventArgs)
{
if (eventArgs.AttackWith.TryGetComponent(out WirecutterComponent wirecutter))
{
Owner.Delete();
var droppedEnt = Owner.EntityManager.SpawnEntity("CableStack", eventArgs.ClickLocation);
if (droppedEnt.TryGetComponent<StackComponent>(out var stackComp))
stackComp.Count = 1;
return true;
}
return false;
}
}
}