@@ -61,12 +61,6 @@ namespace Content.Client
|
|||||||
"Interactable",
|
"Interactable",
|
||||||
"Destructible",
|
"Destructible",
|
||||||
"Temperature",
|
"Temperature",
|
||||||
"PowerTransfer",
|
|
||||||
"PowerNode",
|
|
||||||
"PowerProvider",
|
|
||||||
"PowerDevice",
|
|
||||||
"PowerStorage",
|
|
||||||
"PowerGenerator",
|
|
||||||
"Explosive",
|
"Explosive",
|
||||||
"OnUseTimerTrigger",
|
"OnUseTimerTrigger",
|
||||||
"ToolboxElectricalFill",
|
"ToolboxElectricalFill",
|
||||||
@@ -92,7 +86,6 @@ namespace Content.Client
|
|||||||
"Storeable",
|
"Storeable",
|
||||||
"Dice",
|
"Dice",
|
||||||
"Construction",
|
"Construction",
|
||||||
"Apc",
|
|
||||||
"Door",
|
"Door",
|
||||||
"PoweredLight",
|
"PoweredLight",
|
||||||
"Smes",
|
"Smes",
|
||||||
@@ -104,8 +97,8 @@ namespace Content.Client
|
|||||||
"Ammo",
|
"Ammo",
|
||||||
"HitscanWeaponCapacitor",
|
"HitscanWeaponCapacitor",
|
||||||
"PowerCell",
|
"PowerCell",
|
||||||
"WeaponCapacitorCharger",
|
|
||||||
"PowerCellCharger",
|
"PowerCellCharger",
|
||||||
|
"WeaponCapacitorCharger",
|
||||||
"AiController",
|
"AiController",
|
||||||
"Computer",
|
"Computer",
|
||||||
"AsteroidRock",
|
"AsteroidRock",
|
||||||
@@ -175,7 +168,17 @@ namespace Content.Client
|
|||||||
"UnarmedCombat",
|
"UnarmedCombat",
|
||||||
"TimedSpawner",
|
"TimedSpawner",
|
||||||
"Buckle",
|
"Buckle",
|
||||||
"Strap"
|
"Strap",
|
||||||
|
"NodeContainer",
|
||||||
|
"PowerSupplier",
|
||||||
|
"PowerConsumer",
|
||||||
|
"Battery",
|
||||||
|
"BatteryStorage",
|
||||||
|
"BatteryDischarger",
|
||||||
|
"Apc",
|
||||||
|
"PowerProvider",
|
||||||
|
"PowerReceiver",
|
||||||
|
"Wire",
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var ignoreName in registerIgnore)
|
foreach (var ignoreName in registerIgnore)
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
using Content.Shared.GameObjects.Components.Power;
|
|
||||||
using Robust.Client.UserInterface.Controls;
|
|
||||||
using Robust.Client.UserInterface.CustomControls;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
|
||||||
using Robust.Shared.Interfaces.Network;
|
|
||||||
using Robust.Shared.Players;
|
|
||||||
|
|
||||||
namespace Content.Client.GameObjects.Components.Power
|
|
||||||
{
|
|
||||||
[RegisterComponent]
|
|
||||||
public class PowerDebugTool : SharedPowerDebugTool
|
|
||||||
{
|
|
||||||
SS14Window LastWindow;
|
|
||||||
public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession session = null)
|
|
||||||
{
|
|
||||||
base.HandleNetworkMessage(message, channel, session);
|
|
||||||
|
|
||||||
switch (message)
|
|
||||||
{
|
|
||||||
case OpenDataWindowMsg msg:
|
|
||||||
if (LastWindow != null && !LastWindow.Disposed)
|
|
||||||
{
|
|
||||||
LastWindow.Dispose();
|
|
||||||
}
|
|
||||||
LastWindow = new SS14Window()
|
|
||||||
{
|
|
||||||
Title = "Power Debug Tool",
|
|
||||||
};
|
|
||||||
LastWindow.Contents.AddChild(new Label() { Text = msg.Data });
|
|
||||||
LastWindow.Open();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Client.GameObjects.Components.Gravity;
|
using Content.Client.GameObjects.Components.Gravity;
|
||||||
using Content.Server.GameObjects.Components.Gravity;
|
using Content.Server.GameObjects.Components.Gravity;
|
||||||
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
using Content.Server.GameObjects.Components.Power;
|
using Content.Server.GameObjects.Components.Power;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
@@ -40,11 +41,11 @@ namespace Content.IntegrationTests.Tests
|
|||||||
|
|
||||||
generator = entityMan.SpawnEntity("GravityGenerator", new GridCoordinates(new Vector2(0, 0), grid2.Index));
|
generator = entityMan.SpawnEntity("GravityGenerator", new GridCoordinates(new Vector2(0, 0), grid2.Index));
|
||||||
Assert.That(generator.HasComponent<GravityGeneratorComponent>());
|
Assert.That(generator.HasComponent<GravityGeneratorComponent>());
|
||||||
Assert.That(generator.HasComponent<PowerDeviceComponent>());
|
Assert.That(generator.HasComponent<PowerReceiverComponent>());
|
||||||
var generatorComponent = generator.GetComponent<GravityGeneratorComponent>();
|
var generatorComponent = generator.GetComponent<GravityGeneratorComponent>();
|
||||||
var powerComponent = generator.GetComponent<PowerDeviceComponent>();
|
var powerComponent = generator.GetComponent<PowerReceiverComponent>();
|
||||||
Assert.AreEqual(generatorComponent.Status, GravityGeneratorStatus.Unpowered);
|
Assert.AreEqual(generatorComponent.Status, GravityGeneratorStatus.Unpowered);
|
||||||
powerComponent.ExternalPowered = true;
|
powerComponent.NeedsPower = false;
|
||||||
});
|
});
|
||||||
server.RunTicks(1);
|
server.RunTicks(1);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using Content.Server.Interfaces;
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
|
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||||
|
using Content.Server.Interfaces;
|
||||||
using Content.Server.AI.WorldState;
|
using Content.Server.AI.WorldState;
|
||||||
using Content.Server.Interfaces.Chat;
|
using Content.Server.Interfaces.Chat;
|
||||||
using Content.Server.Interfaces.GameTicking;
|
using Content.Server.Interfaces.GameTicking;
|
||||||
@@ -75,7 +77,8 @@ namespace Content.Server
|
|||||||
logManager.GetSawmill("Storage").Level = LogLevel.Info;
|
logManager.GetSawmill("Storage").Level = LogLevel.Info;
|
||||||
|
|
||||||
IoCManager.Resolve<IServerPreferencesManager>().StartInit();
|
IoCManager.Resolve<IServerPreferencesManager>().StartInit();
|
||||||
|
IoCManager.Resolve<INodeGroupFactory>().Initialize();
|
||||||
|
IoCManager.Resolve<INodeFactory>().Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostInit()
|
public override void PostInit()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.GameObjects.Components.Power;
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Server.Interfaces.GameObjects;
|
using Robust.Server.Interfaces.GameObjects;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -26,7 +26,7 @@ namespace Content.Server.GameObjects.Components.BarSign
|
|||||||
|
|
||||||
private string _currentSign;
|
private string _currentSign;
|
||||||
|
|
||||||
private PowerDeviceComponent _power;
|
private PowerReceiverComponent _power;
|
||||||
private SpriteComponent _sprite;
|
private SpriteComponent _sprite;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
@@ -80,7 +80,7 @@ namespace Content.Server.GameObjects.Components.BarSign
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
_power = Owner.GetComponent<PowerDeviceComponent>();
|
_power = Owner.GetComponent<PowerReceiverComponent>();
|
||||||
_sprite = Owner.GetComponent<SpriteComponent>();
|
_sprite = Owner.GetComponent<SpriteComponent>();
|
||||||
|
|
||||||
_power.OnPowerStateChanged += PowerOnOnPowerStateChanged;
|
_power.OnPowerStateChanged += PowerOnOnPowerStateChanged;
|
||||||
@@ -88,6 +88,12 @@ namespace Content.Server.GameObjects.Components.BarSign
|
|||||||
UpdateSignInfo();
|
UpdateSignInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnRemove()
|
||||||
|
{
|
||||||
|
_power.OnPowerStateChanged -= PowerOnOnPowerStateChanged;
|
||||||
|
base.OnRemove();
|
||||||
|
}
|
||||||
|
|
||||||
private void PowerOnOnPowerStateChanged(object sender, PowerStateEventArgs e)
|
private void PowerOnOnPowerStateChanged(object sender, PowerStateEventArgs e)
|
||||||
{
|
{
|
||||||
UpdateSignInfo();
|
UpdateSignInfo();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Content.Server.Cargo;
|
using Content.Server.Cargo;
|
||||||
using Content.Server.GameObjects.Components.Power;
|
using Content.Server.GameObjects.Components.Power;
|
||||||
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
using Content.Shared.GameObjects.Components.Cargo;
|
using Content.Shared.GameObjects.Components.Cargo;
|
||||||
using Content.Shared.Prototypes.Cargo;
|
using Content.Shared.Prototypes.Cargo;
|
||||||
@@ -65,8 +66,8 @@ namespace Content.Server.GameObjects.Components.Cargo
|
|||||||
|
|
||||||
private bool _requestOnly = false;
|
private bool _requestOnly = false;
|
||||||
|
|
||||||
private PowerDeviceComponent _powerDevice;
|
private PowerReceiverComponent _powerReceiver;
|
||||||
private bool Powered => _powerDevice.Powered;
|
private bool Powered => _powerReceiver.Powered;
|
||||||
private CargoConsoleSystem _cargoConsoleSystem;
|
private CargoConsoleSystem _cargoConsoleSystem;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
@@ -76,7 +77,7 @@ namespace Content.Server.GameObjects.Components.Cargo
|
|||||||
Orders = Owner.GetComponent<CargoOrderDatabaseComponent>();
|
Orders = Owner.GetComponent<CargoOrderDatabaseComponent>();
|
||||||
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(CargoConsoleUiKey.Key);
|
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(CargoConsoleUiKey.Key);
|
||||||
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
|
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
|
||||||
_powerDevice = Owner.GetComponent<PowerDeviceComponent>();
|
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
|
||||||
_cargoConsoleSystem = EntitySystem.Get<CargoConsoleSystem>();
|
_cargoConsoleSystem = EntitySystem.Get<CargoConsoleSystem>();
|
||||||
BankAccount = _cargoConsoleSystem.StationAccount;
|
BankAccount = _cargoConsoleSystem.StationAccount;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ using Robust.Shared.Serialization;
|
|||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
using Robust.Server.GameObjects.EntitySystems;
|
using Robust.Server.GameObjects.EntitySystems;
|
||||||
using Robust.Shared.GameObjects.Systems;
|
using Robust.Shared.GameObjects.Systems;
|
||||||
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Chemistry
|
namespace Content.Server.GameObjects.Components.Chemistry
|
||||||
{
|
{
|
||||||
@@ -51,9 +52,8 @@ namespace Content.Server.GameObjects.Components.Chemistry
|
|||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
private SolutionComponent Solution => _beakerContainer.ContainedEntity.GetComponent<SolutionComponent>();
|
private SolutionComponent Solution => _beakerContainer.ContainedEntity.GetComponent<SolutionComponent>();
|
||||||
|
|
||||||
///implementing PowerDeviceComponent
|
private PowerReceiverComponent _powerReceiver;
|
||||||
private PowerDeviceComponent _powerDevice;
|
private bool Powered => _powerReceiver.Powered;
|
||||||
private bool Powered => _powerDevice.Powered;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -80,7 +80,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
|
|||||||
|
|
||||||
_beakerContainer =
|
_beakerContainer =
|
||||||
ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-reagentContainerContainer", Owner);
|
ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-reagentContainerContainer", Owner);
|
||||||
_powerDevice = Owner.GetComponent<PowerDeviceComponent>();
|
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
|
||||||
|
|
||||||
InitializeFromPrototype();
|
InitializeFromPrototype();
|
||||||
UpdateUserInterface();
|
UpdateUserInterface();
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
using Content.Server.GameObjects.Components.Power;
|
using Content.Server.GameObjects.Components.Power;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
using Content.Server.Interfaces.GameTicking;
|
using Content.Server.Interfaces.GameTicking;
|
||||||
@@ -21,8 +22,8 @@ namespace Content.Server.GameObjects.Components.Command
|
|||||||
#pragma warning restore 649
|
#pragma warning restore 649
|
||||||
|
|
||||||
private BoundUserInterface _userInterface;
|
private BoundUserInterface _userInterface;
|
||||||
private PowerDeviceComponent _powerDevice;
|
private PowerReceiverComponent _powerReceiver;
|
||||||
private bool Powered => _powerDevice.Powered;
|
private bool Powered => _powerReceiver.Powered;
|
||||||
private RoundEndSystem RoundEndSystem => _entitySystemManager.GetEntitySystem<RoundEndSystem>();
|
private RoundEndSystem RoundEndSystem => _entitySystemManager.GetEntitySystem<RoundEndSystem>();
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
@@ -31,7 +32,7 @@ namespace Content.Server.GameObjects.Components.Command
|
|||||||
|
|
||||||
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(CommunicationsConsoleUiKey.Key);
|
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(CommunicationsConsoleUiKey.Key);
|
||||||
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
|
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
|
||||||
_powerDevice = Owner.GetComponent<PowerDeviceComponent>();
|
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
|
||||||
|
|
||||||
RoundEndSystem.OnRoundEndCountdownStarted += UpdateBoundInterface;
|
RoundEndSystem.OnRoundEndCountdownStarted += UpdateBoundInterface;
|
||||||
RoundEndSystem.OnRoundEndCountdownCancelled += UpdateBoundInterface;
|
RoundEndSystem.OnRoundEndCountdownCancelled += UpdateBoundInterface;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Content.Server.GameObjects.Components.Power;
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
using Content.Shared.GameObjects.Components;
|
using Content.Shared.GameObjects.Components;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -12,18 +12,28 @@ namespace Content.Server.GameObjects.Components
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
if (Owner.TryGetComponent(out PowerDeviceComponent powerDevice))
|
if (Owner.TryGetComponent(out PowerReceiverComponent powerReceiver))
|
||||||
{
|
{
|
||||||
powerDevice.OnPowerStateChanged += PowerDeviceOnOnPowerStateChanged;
|
powerReceiver.OnPowerStateChanged += PowerReceiverOnOnPowerStateChanged;
|
||||||
|
|
||||||
if (Owner.TryGetComponent(out AppearanceComponent appearance))
|
if (Owner.TryGetComponent(out AppearanceComponent appearance))
|
||||||
{
|
{
|
||||||
appearance.SetData(ComputerVisuals.Powered, powerDevice.Powered);
|
appearance.SetData(ComputerVisuals.Powered, powerReceiver.Powered);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PowerDeviceOnOnPowerStateChanged(object sender, PowerStateEventArgs e)
|
public override void OnRemove()
|
||||||
|
{
|
||||||
|
if (Owner.TryGetComponent(out PowerReceiverComponent powerReceiver))
|
||||||
|
{
|
||||||
|
powerReceiver.OnPowerStateChanged -= PowerReceiverOnOnPowerStateChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnRemove();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PowerReceiverOnOnPowerStateChanged(object sender, PowerStateEventArgs e)
|
||||||
{
|
{
|
||||||
if (Owner.TryGetComponent(out AppearanceComponent appearance))
|
if (Owner.TryGetComponent(out AppearanceComponent appearance))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Content.Server.GameObjects.Components.Interactable;
|
using Content.Server.GameObjects.Components.Interactable;
|
||||||
using Content.Server.GameObjects.Components.Power;
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
|
using Content.Server.GameObjects.Components.Power.PowerNetComponents;
|
||||||
using Content.Server.GameObjects.Components.VendingMachines;
|
using Content.Server.GameObjects.Components.VendingMachines;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
using Content.Server.Interfaces;
|
using Content.Server.Interfaces;
|
||||||
@@ -31,7 +32,7 @@ namespace Content.Server.GameObjects.Components.Doors
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private static readonly TimeSpan PowerWiresTimeout = TimeSpan.FromSeconds(5.0);
|
private static readonly TimeSpan PowerWiresTimeout = TimeSpan.FromSeconds(5.0);
|
||||||
|
|
||||||
private PowerDeviceComponent _powerDevice;
|
private PowerReceiverComponent _powerReceiver;
|
||||||
private WiresComponent _wires;
|
private WiresComponent _wires;
|
||||||
|
|
||||||
private CancellationTokenSource _powerWiresPulsedTimerCancel;
|
private CancellationTokenSource _powerWiresPulsedTimerCancel;
|
||||||
@@ -82,7 +83,7 @@ namespace Content.Server.GameObjects.Components.Doors
|
|||||||
|
|
||||||
private void UpdatePowerCutStatus()
|
private void UpdatePowerCutStatus()
|
||||||
{
|
{
|
||||||
_powerDevice.IsPowerCut = PowerWiresPulsed ||
|
_powerReceiver.PowerDisabled = PowerWiresPulsed ||
|
||||||
_wires.IsWireCut(Wires.MainPower) ||
|
_wires.IsWireCut(Wires.MainPower) ||
|
||||||
_wires.IsWireCut(Wires.BackupPower);
|
_wires.IsWireCut(Wires.BackupPower);
|
||||||
}
|
}
|
||||||
@@ -100,10 +101,20 @@ namespace Content.Server.GameObjects.Components.Doors
|
|||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
_powerDevice = Owner.GetComponent<PowerDeviceComponent>();
|
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
|
||||||
_wires = Owner.GetComponent<WiresComponent>();
|
_wires = Owner.GetComponent<WiresComponent>();
|
||||||
|
|
||||||
_powerDevice.OnPowerStateChanged += PowerDeviceOnOnPowerStateChanged;
|
_powerReceiver.OnPowerStateChanged += PowerDeviceOnOnPowerStateChanged;
|
||||||
|
if (Owner.TryGetComponent(out AppearanceComponent appearance))
|
||||||
|
{
|
||||||
|
appearance.SetData(DoorVisuals.Powered, _powerReceiver.Powered);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnRemove()
|
||||||
|
{
|
||||||
|
_powerReceiver.OnPowerStateChanged -= PowerDeviceOnOnPowerStateChanged;
|
||||||
|
base.OnRemove();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PowerDeviceOnOnPowerStateChanged(object sender, PowerStateEventArgs e)
|
private void PowerDeviceOnOnPowerStateChanged(object sender, PowerStateEventArgs e)
|
||||||
@@ -217,7 +228,7 @@ namespace Content.Server.GameObjects.Components.Doors
|
|||||||
|
|
||||||
private bool IsPowered()
|
private bool IsPowered()
|
||||||
{
|
{
|
||||||
return _powerDevice.Powered;
|
return _powerReceiver.Powered;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool InteractUsing(InteractUsingEventArgs eventArgs)
|
public bool InteractUsing(InteractUsingEventArgs eventArgs)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Content.Server.GameObjects.Components.Damage;
|
using Content.Server.GameObjects.Components.Damage;
|
||||||
using Content.Server.GameObjects.Components.Interactable;
|
using Content.Server.GameObjects.Components.Interactable;
|
||||||
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
using Content.Server.GameObjects.Components.Power;
|
using Content.Server.GameObjects.Components.Power;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
using Content.Server.Interfaces;
|
using Content.Server.Interfaces;
|
||||||
@@ -27,7 +28,7 @@ namespace Content.Server.GameObjects.Components.Gravity
|
|||||||
{
|
{
|
||||||
private BoundUserInterface _userInterface;
|
private BoundUserInterface _userInterface;
|
||||||
|
|
||||||
private PowerDeviceComponent _powerDevice;
|
private PowerReceiverComponent _powerReceiver;
|
||||||
|
|
||||||
private SpriteComponent _sprite;
|
private SpriteComponent _sprite;
|
||||||
|
|
||||||
@@ -37,7 +38,7 @@ namespace Content.Server.GameObjects.Components.Gravity
|
|||||||
|
|
||||||
private GravityGeneratorStatus _status;
|
private GravityGeneratorStatus _status;
|
||||||
|
|
||||||
public bool Powered => _powerDevice.Powered;
|
public bool Powered => _powerReceiver.Powered;
|
||||||
|
|
||||||
public bool SwitchedOn => _switchedOn;
|
public bool SwitchedOn => _switchedOn;
|
||||||
|
|
||||||
@@ -74,7 +75,7 @@ namespace Content.Server.GameObjects.Components.Gravity
|
|||||||
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
|
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
|
||||||
.GetBoundUserInterface(GravityGeneratorUiKey.Key);
|
.GetBoundUserInterface(GravityGeneratorUiKey.Key);
|
||||||
_userInterface.OnReceiveMessage += HandleUIMessage;
|
_userInterface.OnReceiveMessage += HandleUIMessage;
|
||||||
_powerDevice = Owner.GetComponent<PowerDeviceComponent>();
|
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
|
||||||
_sprite = Owner.GetComponent<SpriteComponent>();
|
_sprite = Owner.GetComponent<SpriteComponent>();
|
||||||
_switchedOn = true;
|
_switchedOn = true;
|
||||||
_intact = true;
|
_intact = true;
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using Content.Server.GameObjects.Components.Power;
|
using Content.Server.GameObjects.Components.Power;
|
||||||
using Content.Server.GameObjects.Components.Sound;
|
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
using Content.Server.Interfaces.GameObjects;
|
using Content.Server.Interfaces.GameObjects;
|
||||||
using Content.Server.Utility;
|
|
||||||
using Content.Shared.GameObjects;
|
using Content.Shared.GameObjects;
|
||||||
using Content.Shared.GameObjects.Components;
|
using Content.Shared.GameObjects.Components;
|
||||||
using Content.Shared.GameObjects.EntitySystems;
|
using Content.Shared.GameObjects.EntitySystems;
|
||||||
@@ -18,6 +16,7 @@ using Robust.Shared.IoC;
|
|||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Interactable
|
namespace Content.Server.GameObjects.Components.Interactable
|
||||||
{
|
{
|
||||||
@@ -39,13 +38,13 @@ namespace Content.Server.GameObjects.Components.Interactable
|
|||||||
private ClothingComponent _clothingComponent;
|
private ClothingComponent _clothingComponent;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
private PowerCellComponent Cell
|
private BatteryComponent Cell
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_cellContainer.ContainedEntity == null) return null;
|
if (_cellContainer.ContainedEntity == null) return null;
|
||||||
|
|
||||||
_cellContainer.ContainedEntity.TryGetComponent(out PowerCellComponent cell);
|
_cellContainer.ContainedEntity.TryGetComponent(out BatteryComponent cell);
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,7 +57,7 @@ namespace Content.Server.GameObjects.Components.Interactable
|
|||||||
|
|
||||||
bool IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
|
bool IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
if (!eventArgs.Using.HasComponent<PowerCellComponent>()) return false;
|
if (!eventArgs.Using.HasComponent<BatteryComponent>()) return false;
|
||||||
|
|
||||||
if (Cell != null) return false;
|
if (Cell != null) return false;
|
||||||
|
|
||||||
@@ -100,7 +99,8 @@ namespace Content.Server.GameObjects.Components.Interactable
|
|||||||
_spriteComponent = Owner.GetComponent<SpriteComponent>();
|
_spriteComponent = Owner.GetComponent<SpriteComponent>();
|
||||||
Owner.TryGetComponent(out _clothingComponent);
|
Owner.TryGetComponent(out _clothingComponent);
|
||||||
_cellContainer =
|
_cellContainer =
|
||||||
ContainerManagerComponent.Ensure<ContainerSlot>("flashlight_cell_container", Owner, out var existed);
|
ContainerManagerComponent.Ensure<ContainerSlot>("flashlight_cell_container", Owner, out _);
|
||||||
|
Dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -160,7 +160,7 @@ namespace Content.Server.GameObjects.Components.Interactable
|
|||||||
// To prevent having to worry about frame time in here.
|
// To prevent having to worry about frame time in here.
|
||||||
// Let's just say you need a whole second of charge before you can turn it on.
|
// Let's just say you need a whole second of charge before you can turn it on.
|
||||||
// Simple enough.
|
// Simple enough.
|
||||||
if (cell.AvailableCharge(1) < Wattage)
|
if (Wattage > cell.CurrentCharge)
|
||||||
{
|
{
|
||||||
EntitySystem.Get<AudioSystem>().PlayFromEntity("/Audio/machines/button.ogg", Owner);
|
EntitySystem.Get<AudioSystem>().PlayFromEntity("/Audio/machines/button.ogg", Owner);
|
||||||
_notifyManager.PopupMessage(Owner, user, _localizationManager.GetString("Dead cell..."));
|
_notifyManager.PopupMessage(Owner, user, _localizationManager.GetString("Dead cell..."));
|
||||||
@@ -189,7 +189,7 @@ namespace Content.Server.GameObjects.Components.Interactable
|
|||||||
if (!Activated) return;
|
if (!Activated) return;
|
||||||
|
|
||||||
var cell = Cell;
|
var cell = Cell;
|
||||||
if (cell == null || !cell.TryDeductWattage(Wattage, frameTime)) TurnOff();
|
if (cell == null || !cell.TryUseCharge(Wattage * frameTime)) TurnOff();
|
||||||
|
|
||||||
Dirty();
|
Dirty();
|
||||||
}
|
}
|
||||||
@@ -229,14 +229,14 @@ namespace Content.Server.GameObjects.Components.Interactable
|
|||||||
return new HandheldLightComponentState(null);
|
return new HandheldLightComponentState(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Cell.AvailableCharge(1) < Wattage)
|
if (Wattage > Cell.CurrentCharge)
|
||||||
{
|
{
|
||||||
// Practically zero.
|
// Practically zero.
|
||||||
// This is so the item status works correctly.
|
// This is so the item status works correctly.
|
||||||
return new HandheldLightComponentState(0);
|
return new HandheldLightComponentState(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new HandheldLightComponentState(Cell.Charge / Cell.Capacity);
|
return new HandheldLightComponentState(Cell.CurrentCharge / Cell.MaxCharge);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Verb]
|
[Verb]
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ namespace Content.Server.GameObjects.Components.Items.Storage.Fill
|
|||||||
{
|
{
|
||||||
if (random.Prob(0.3f))
|
if (random.Prob(0.3f))
|
||||||
{
|
{
|
||||||
Spawn("CableStack");
|
Spawn("ApcExtensionCableStack");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,11 +30,9 @@ namespace Content.Server.GameObjects.Components.Items.Storage.Fill
|
|||||||
Spawn("Screwdriver");
|
Spawn("Screwdriver");
|
||||||
Spawn("Crowbar");
|
Spawn("Crowbar");
|
||||||
Spawn("Wirecutter");
|
Spawn("Wirecutter");
|
||||||
Spawn("CableStack");
|
Spawn("ApcExtensionCableStack");
|
||||||
Spawn("CableStack");
|
Spawn("MVWireStack");
|
||||||
|
Spawn(random.Prob(0.05f) ? "GlovesYellow" : "HVWireStack");
|
||||||
// 5% chance for a pair of fancy insulated gloves, else just a third cable coil.
|
|
||||||
Spawn(random.Prob(0.05f) ? "GlovesYellow" : "CableStack");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace Content.Server.GameObjects.Components.Items.Storage.Fill
|
|||||||
Spawn("Wirecutter");
|
Spawn("Wirecutter");
|
||||||
Spawn("Welder");
|
Spawn("Welder");
|
||||||
Spawn("Multitool");
|
Spawn("Multitool");
|
||||||
Spawn("CableStack");
|
Spawn("ApcExtensionCableStack");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ using Content.Server.Interfaces.Chat;
|
|||||||
using Content.Server.BodySystem;
|
using Content.Server.BodySystem;
|
||||||
using Content.Shared.BodySystem;
|
using Content.Shared.BodySystem;
|
||||||
using Robust.Shared.GameObjects.Systems;
|
using Robust.Shared.GameObjects.Systems;
|
||||||
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Kitchen
|
namespace Content.Server.GameObjects.Components.Kitchen
|
||||||
{
|
{
|
||||||
@@ -63,7 +64,7 @@ namespace Content.Server.GameObjects.Components.Kitchen
|
|||||||
private uint _currentCookTimerTime = 1;
|
private uint _currentCookTimerTime = 1;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private bool _powered => _powerDevice.Powered;
|
private bool _powered => _powerReceiver.Powered;
|
||||||
private bool _hasContents => _solution.ReagentList.Count > 0 || _storage.ContainedEntities.Count > 0;
|
private bool _hasContents => _solution.ReagentList.Count > 0 || _storage.ContainedEntities.Count > 0;
|
||||||
private bool _uiDirty = true;
|
private bool _uiDirty = true;
|
||||||
private bool _lostPower = false;
|
private bool _lostPower = false;
|
||||||
@@ -72,7 +73,7 @@ namespace Content.Server.GameObjects.Components.Kitchen
|
|||||||
void ISolutionChange.SolutionChanged(SolutionChangeEventArgs eventArgs) => _uiDirty = true;
|
void ISolutionChange.SolutionChanged(SolutionChangeEventArgs eventArgs) => _uiDirty = true;
|
||||||
private AudioSystem _audioSystem;
|
private AudioSystem _audioSystem;
|
||||||
private AppearanceComponent _appearance;
|
private AppearanceComponent _appearance;
|
||||||
private PowerDeviceComponent _powerDevice;
|
private PowerReceiverComponent _powerReceiver;
|
||||||
private BoundUserInterface _userInterface;
|
private BoundUserInterface _userInterface;
|
||||||
private Container _storage;
|
private Container _storage;
|
||||||
|
|
||||||
@@ -95,7 +96,7 @@ namespace Content.Server.GameObjects.Components.Kitchen
|
|||||||
|
|
||||||
_storage = ContainerManagerComponent.Ensure<Container>("microwave_entity_container", Owner, out var existed);
|
_storage = ContainerManagerComponent.Ensure<Container>("microwave_entity_container", Owner, out var existed);
|
||||||
_appearance = Owner.GetComponent<AppearanceComponent>();
|
_appearance = Owner.GetComponent<AppearanceComponent>();
|
||||||
_powerDevice = Owner.GetComponent<PowerDeviceComponent>();
|
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
|
||||||
_audioSystem = EntitySystem.Get<AudioSystem>();
|
_audioSystem = EntitySystem.Get<AudioSystem>();
|
||||||
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
|
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
|
||||||
.GetBoundUserInterface(MicrowaveUiKey.Key);
|
.GetBoundUserInterface(MicrowaveUiKey.Key);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ using Robust.Shared.GameObjects;
|
|||||||
using Robust.Shared.Interfaces.GameObjects;
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
using Robust.Shared.Maths;
|
using Robust.Shared.Maths;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Medical
|
namespace Content.Server.GameObjects.Components.Medical
|
||||||
{
|
{
|
||||||
@@ -27,9 +28,8 @@ namespace Content.Server.GameObjects.Components.Medical
|
|||||||
private readonly Vector2 _ejectOffset = new Vector2(-0.5f, 0f);
|
private readonly Vector2 _ejectOffset = new Vector2(-0.5f, 0f);
|
||||||
public bool IsOccupied => _bodyContainer.ContainedEntity != null;
|
public bool IsOccupied => _bodyContainer.ContainedEntity != null;
|
||||||
|
|
||||||
///implementing PowerDeviceComponent
|
private PowerReceiverComponent _powerReceiver;
|
||||||
private PowerDeviceComponent _powerDevice;
|
private bool Powered => _powerReceiver.Powered;
|
||||||
private bool Powered => _powerDevice.Powered;
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -38,7 +38,7 @@ namespace Content.Server.GameObjects.Components.Medical
|
|||||||
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
|
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
|
||||||
.GetBoundUserInterface(MedicalScannerUiKey.Key);
|
.GetBoundUserInterface(MedicalScannerUiKey.Key);
|
||||||
_bodyContainer = ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-bodyContainer", Owner);
|
_bodyContainer = ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-bodyContainer", Owner);
|
||||||
_powerDevice = Owner.GetComponent<PowerDeviceComponent>();
|
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
|
||||||
UpdateUserInterface();
|
UpdateUserInterface();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
|
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.NodeContainer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates and maintains a set of <see cref="Node"/>s.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public class NodeContainerComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name => "NodeContainer";
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public IReadOnlyList<Node> Nodes => _nodes;
|
||||||
|
private List<Node> _nodes = new List<Node>();
|
||||||
|
|
||||||
|
#pragma warning disable 649
|
||||||
|
[Dependency] private readonly INodeFactory _nodeFactory;
|
||||||
|
#pragma warning restore 649
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A set of <see cref="NodeGroupID"/>s and <see cref="Node"/> implementation names
|
||||||
|
/// to be created and held in this container.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
private Dictionary<NodeGroupID, List<string>> _nodeTypes;
|
||||||
|
|
||||||
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
|
{
|
||||||
|
base.ExposeData(serializer);
|
||||||
|
serializer.DataField(ref _nodeTypes, "nodeTypes", new Dictionary<NodeGroupID, List<string>> { });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Startup()
|
||||||
|
{
|
||||||
|
base.Startup();
|
||||||
|
foreach (var nodeType in _nodeTypes)
|
||||||
|
{
|
||||||
|
var nodeGroupID = nodeType.Key;
|
||||||
|
foreach (var nodeName in nodeType.Value)
|
||||||
|
{
|
||||||
|
_nodes.Add(MakeNewNode(nodeName, nodeGroupID, Owner));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var node in _nodes)
|
||||||
|
{
|
||||||
|
node.OnContainerInitialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnRemove()
|
||||||
|
{
|
||||||
|
foreach (var node in _nodes)
|
||||||
|
{
|
||||||
|
node.OnContainerRemove();
|
||||||
|
}
|
||||||
|
_nodes = null;
|
||||||
|
base.OnRemove();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node MakeNewNode(string nodeName, NodeGroupID groupID, IEntity owner)
|
||||||
|
{
|
||||||
|
return _nodeFactory.MakeNode(nodeName, groupID, owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
using Content.Server.GameObjects.Components.Power;
|
||||||
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups
|
||||||
|
{
|
||||||
|
public interface IApcNet
|
||||||
|
{
|
||||||
|
void AddApc(ApcComponent apc);
|
||||||
|
|
||||||
|
void RemoveApc(ApcComponent apc);
|
||||||
|
|
||||||
|
void AddPowerProvider(PowerProviderComponent provider);
|
||||||
|
|
||||||
|
void RemovePowerProvider(PowerProviderComponent provider);
|
||||||
|
|
||||||
|
void UpdatePowerProviderReceivers(PowerProviderComponent provider);
|
||||||
|
|
||||||
|
void Update(float frameTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NodeGroup(NodeGroupID.Apc)]
|
||||||
|
public class ApcNetNodeGroup : BaseNetConnectorNodeGroup<BaseApcNetComponent, IApcNet>, IApcNet
|
||||||
|
{
|
||||||
|
[ViewVariables]
|
||||||
|
private readonly Dictionary<ApcComponent, BatteryComponent> _apcBatteries = new Dictionary<ApcComponent, BatteryComponent>();
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private readonly Dictionary<PowerProviderComponent, List<PowerReceiverComponent>> _providerReceivers = new Dictionary<PowerProviderComponent, List<PowerReceiverComponent>>();
|
||||||
|
|
||||||
|
//Debug property
|
||||||
|
[ViewVariables]
|
||||||
|
private int TotalReceivers => _providerReceivers.SelectMany(kvp => kvp.Value).Count();
|
||||||
|
|
||||||
|
private IEnumerable<BatteryComponent> AvailableBatteries => _apcBatteries.Where(kvp => kvp.Key.MainBreakerEnabled).Select(kvp => kvp.Value);
|
||||||
|
|
||||||
|
public static readonly IApcNet NullNet = new NullApcNet();
|
||||||
|
|
||||||
|
#region IApcNet Methods
|
||||||
|
|
||||||
|
protected override void SetNetConnectorNet(BaseApcNetComponent netConnectorComponent)
|
||||||
|
{
|
||||||
|
netConnectorComponent.Net = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddApc(ApcComponent apc)
|
||||||
|
{
|
||||||
|
_apcBatteries.Add(apc, apc.Battery);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveApc(ApcComponent apc)
|
||||||
|
{
|
||||||
|
_apcBatteries.Remove(apc);
|
||||||
|
if (!_apcBatteries.Any())
|
||||||
|
{
|
||||||
|
foreach (var receiver in _providerReceivers.SelectMany(kvp => kvp.Value))
|
||||||
|
{
|
||||||
|
receiver.HasApcPower = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddPowerProvider(PowerProviderComponent provider)
|
||||||
|
{
|
||||||
|
_providerReceivers.Add(provider, provider.LinkedReceivers.ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemovePowerProvider(PowerProviderComponent provider)
|
||||||
|
{
|
||||||
|
_providerReceivers.Remove(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdatePowerProviderReceivers(PowerProviderComponent provider)
|
||||||
|
{
|
||||||
|
Debug.Assert(_providerReceivers.ContainsKey(provider));
|
||||||
|
_providerReceivers[provider] = provider.LinkedReceivers.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(float frameTime)
|
||||||
|
{
|
||||||
|
var totalCharge = 0.0;
|
||||||
|
var totalMaxCharge = 0;
|
||||||
|
foreach (var battery in AvailableBatteries)
|
||||||
|
{
|
||||||
|
totalCharge += battery.CurrentCharge;
|
||||||
|
totalMaxCharge += battery.MaxCharge;
|
||||||
|
}
|
||||||
|
var availablePowerFraction = totalCharge / totalMaxCharge;
|
||||||
|
foreach (var receiver in _providerReceivers.SelectMany(kvp => kvp.Value))
|
||||||
|
{
|
||||||
|
receiver.HasApcPower = TryUsePower(receiver.Load * frameTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryUsePower(float neededCharge)
|
||||||
|
{
|
||||||
|
foreach (var battery in AvailableBatteries)
|
||||||
|
{
|
||||||
|
if (battery.TryUseCharge(neededCharge)) //simplification - all power needed must come from one battery
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private class NullApcNet : IApcNet
|
||||||
|
{
|
||||||
|
public void AddApc(ApcComponent apc) { }
|
||||||
|
public void AddPowerProvider(PowerProviderComponent provider) { }
|
||||||
|
public void RemoveApc(ApcComponent apc) { }
|
||||||
|
public void RemovePowerProvider(PowerProviderComponent provider) { }
|
||||||
|
public void UpdatePowerProviderReceivers(PowerProviderComponent provider) { }
|
||||||
|
public void Update(float frameTime) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using Content.Server.GameObjects.Components.Power;
|
||||||
|
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups
|
||||||
|
{
|
||||||
|
public abstract class BaseNetConnectorNodeGroup<TNetConnector, TNetType> : BaseNodeGroup where TNetConnector : BaseNetConnectorComponent<TNetType>
|
||||||
|
{
|
||||||
|
private readonly Dictionary<Node, List<TNetConnector>> _netConnectorComponents = new Dictionary<Node, List<TNetConnector>>();
|
||||||
|
|
||||||
|
protected override void OnAddNode(Node node)
|
||||||
|
{
|
||||||
|
var newNetConnectorComponents = node.Owner
|
||||||
|
.GetAllComponents<TNetConnector>()
|
||||||
|
.Where(powerComp => (NodeGroupID) powerComp.Voltage == node.NodeGroupID)
|
||||||
|
.ToList();
|
||||||
|
_netConnectorComponents.Add(node, newNetConnectorComponents);
|
||||||
|
foreach (var netConnectorComponent in newNetConnectorComponents)
|
||||||
|
{
|
||||||
|
SetNetConnectorNet(netConnectorComponent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void SetNetConnectorNet(TNetConnector netConnectorComponent);
|
||||||
|
|
||||||
|
protected override void OnRemoveNode(Node node)
|
||||||
|
{
|
||||||
|
foreach (var netConnectorComponent in _netConnectorComponents[node])
|
||||||
|
{
|
||||||
|
netConnectorComponent.ClearNet();
|
||||||
|
}
|
||||||
|
_netConnectorComponents.Remove(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Maintains a collection of <see cref="Node"/>s, and performs operations requiring a list of
|
||||||
|
/// all connected <see cref="Node"/>s.
|
||||||
|
/// </summary>
|
||||||
|
public interface INodeGroup
|
||||||
|
{
|
||||||
|
public IReadOnlyList<Node> Nodes { get; }
|
||||||
|
|
||||||
|
void AddNode(Node node);
|
||||||
|
|
||||||
|
void RemoveNode(Node node);
|
||||||
|
|
||||||
|
void CombineGroup(INodeGroup newGroup);
|
||||||
|
|
||||||
|
void BeforeCombine();
|
||||||
|
|
||||||
|
void AfterCombine();
|
||||||
|
|
||||||
|
void BeforeRemakeSpread();
|
||||||
|
|
||||||
|
void AfterRemakeSpread();
|
||||||
|
}
|
||||||
|
|
||||||
|
[NodeGroup(NodeGroupID.Default)]
|
||||||
|
public class BaseNodeGroup : INodeGroup
|
||||||
|
{
|
||||||
|
[ViewVariables]
|
||||||
|
public IReadOnlyList<Node> Nodes => _nodes;
|
||||||
|
private readonly List<Node> _nodes = new List<Node>();
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public int NodeCount => Nodes.Count;
|
||||||
|
|
||||||
|
public static readonly INodeGroup NullGroup = new NullNodeGroup();
|
||||||
|
|
||||||
|
public void AddNode(Node node)
|
||||||
|
{
|
||||||
|
_nodes.Add(node);
|
||||||
|
OnAddNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveNode(Node node)
|
||||||
|
{
|
||||||
|
_nodes.Remove(node);
|
||||||
|
OnRemoveNode(node);
|
||||||
|
RemakeGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CombineGroup(INodeGroup newGroup)
|
||||||
|
{
|
||||||
|
if (newGroup.Nodes.Count < Nodes.Count)
|
||||||
|
{
|
||||||
|
newGroup.CombineGroup(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BeforeCombine();
|
||||||
|
newGroup.BeforeCombine();
|
||||||
|
foreach (var node in Nodes)
|
||||||
|
{
|
||||||
|
node.NodeGroup = newGroup;
|
||||||
|
}
|
||||||
|
AfterCombine();
|
||||||
|
newGroup.AfterCombine();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Causes all <see cref="Node"/>s to remake their groups. Called when a <see cref="Node"/> is removed
|
||||||
|
/// and may have split a group in two, so multiple new groups may need to be formed.
|
||||||
|
/// </summary>
|
||||||
|
private void RemakeGroup()
|
||||||
|
{
|
||||||
|
BeforeRemake();
|
||||||
|
foreach (var node in Nodes)
|
||||||
|
{
|
||||||
|
node.ClearNodeGroup();
|
||||||
|
}
|
||||||
|
foreach (var node in Nodes)
|
||||||
|
{
|
||||||
|
if (node.TryAssignGroupIfNeeded())
|
||||||
|
{
|
||||||
|
node.StartSpreadingGroup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnAddNode(Node node) { }
|
||||||
|
|
||||||
|
protected virtual void OnRemoveNode(Node node) { }
|
||||||
|
|
||||||
|
protected virtual void BeforeRemake() { }
|
||||||
|
|
||||||
|
protected virtual void AfterRemake() { }
|
||||||
|
|
||||||
|
public virtual void BeforeCombine() { }
|
||||||
|
|
||||||
|
public virtual void AfterCombine() { }
|
||||||
|
|
||||||
|
public virtual void BeforeRemakeSpread() { }
|
||||||
|
|
||||||
|
public virtual void AfterRemakeSpread() { }
|
||||||
|
|
||||||
|
private class NullNodeGroup : INodeGroup
|
||||||
|
{
|
||||||
|
public IReadOnlyList<Node> Nodes => _nodes;
|
||||||
|
private readonly List<Node> _nodes = new List<Node>();
|
||||||
|
public void AddNode(Node node) { }
|
||||||
|
public void CombineGroup(INodeGroup newGroup) { }
|
||||||
|
public void RemoveNode(Node node) { }
|
||||||
|
public void BeforeCombine() { }
|
||||||
|
public void AfterCombine() { }
|
||||||
|
public void BeforeRemakeSpread() { }
|
||||||
|
public void AfterRemakeSpread() { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Associates a <see cref="INodeGroup"/> implementation with a <see cref="NodeGroupID"/>.
|
||||||
|
/// This is used to gurantee all <see cref="INode"/>s of the same <see cref="INode.NodeGroupID"/>
|
||||||
|
/// have the same type of <see cref="INodeGroup"/>. Used by <see cref="INodeGroupFactory"/>.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||||
|
public class NodeGroupAttribute : Attribute
|
||||||
|
{
|
||||||
|
public NodeGroupID[] NodeGroupIDs { get; }
|
||||||
|
|
||||||
|
public NodeGroupAttribute(params NodeGroupID[] nodeGroupTypes)
|
||||||
|
{
|
||||||
|
NodeGroupIDs = nodeGroupTypes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
using Robust.Shared.Interfaces.Reflection;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups
|
||||||
|
{
|
||||||
|
public interface INodeGroupFactory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Performs reflection to associate <see cref="INodeGroup"/> implementations with the
|
||||||
|
/// string specified in their <see cref="NodeGroupAttribute"/>.
|
||||||
|
/// </summary>
|
||||||
|
void Initialize();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a new <see cref="INodeGroup"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
INodeGroup MakeNodeGroup(NodeGroupID nodeGroupType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NodeGroupFactory : INodeGroupFactory
|
||||||
|
{
|
||||||
|
private readonly Dictionary<NodeGroupID, Type> _groupTypes = new Dictionary<NodeGroupID, Type>();
|
||||||
|
|
||||||
|
#pragma warning disable 649
|
||||||
|
[Dependency] private readonly IReflectionManager _reflectionManager;
|
||||||
|
[Dependency] private readonly IDynamicTypeFactory _typeFactory;
|
||||||
|
#pragma warning restore 649
|
||||||
|
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
var nodeGroupTypes = _reflectionManager.GetAllChildren<BaseNodeGroup>();
|
||||||
|
foreach (var nodeGroupType in nodeGroupTypes)
|
||||||
|
{
|
||||||
|
var att = nodeGroupType.GetCustomAttribute<NodeGroupAttribute>();
|
||||||
|
if (att != null)
|
||||||
|
{
|
||||||
|
foreach (var groupID in att.NodeGroupIDs)
|
||||||
|
{
|
||||||
|
_groupTypes.Add(groupID, nodeGroupType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public INodeGroup MakeNodeGroup(NodeGroupID nodeGroupType)
|
||||||
|
{
|
||||||
|
if (_groupTypes.TryGetValue(nodeGroupType, out var type))
|
||||||
|
{
|
||||||
|
return _typeFactory.CreateInstance<INodeGroup>(type);
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"{nodeGroupType} did not have an associated {nameof(INodeGroup)}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum NodeGroupID
|
||||||
|
{
|
||||||
|
Default,
|
||||||
|
HVPower,
|
||||||
|
MVPower,
|
||||||
|
Apc,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
using Content.Server.GameObjects.Components.Power.PowerNetComponents;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups
|
||||||
|
{
|
||||||
|
public interface IPowerNet
|
||||||
|
{
|
||||||
|
void AddSupplier(PowerSupplierComponent supplier);
|
||||||
|
|
||||||
|
void RemoveSupplier(PowerSupplierComponent supplier);
|
||||||
|
|
||||||
|
void UpdateSupplierSupply(PowerSupplierComponent supplier, int oldSupplyRate, int newSupplyRate);
|
||||||
|
|
||||||
|
void AddConsumer(PowerConsumerComponent consumer);
|
||||||
|
|
||||||
|
void RemoveConsumer(PowerConsumerComponent consumer);
|
||||||
|
|
||||||
|
void UpdateConsumerDraw(PowerConsumerComponent consumer, int oldDrawRate, int newDrawRate);
|
||||||
|
|
||||||
|
void UpdateConsumerPriority(PowerConsumerComponent consumer, Priority oldPriority, Priority newPriority);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NodeGroup(NodeGroupID.HVPower, NodeGroupID.MVPower)]
|
||||||
|
public class PowerNetNodeGroup : BaseNetConnectorNodeGroup<BasePowerNetComponent, IPowerNet>, IPowerNet
|
||||||
|
{
|
||||||
|
[ViewVariables]
|
||||||
|
private readonly List<PowerSupplierComponent> _suppliers = new List<PowerSupplierComponent>();
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private int _totalSupply = 0;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private readonly Dictionary<Priority, List<PowerConsumerComponent>> _consumersByPriority = new Dictionary<Priority, List<PowerConsumerComponent>>();
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private readonly Dictionary<Priority, int> _drawByPriority = new Dictionary<Priority, int>();
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private bool _supressPowerRecalculation = false;
|
||||||
|
|
||||||
|
public static readonly IPowerNet NullNet = new NullPowerNet();
|
||||||
|
|
||||||
|
public PowerNetNodeGroup()
|
||||||
|
{
|
||||||
|
foreach(Priority priority in Enum.GetValues(typeof(Priority)))
|
||||||
|
{
|
||||||
|
_consumersByPriority.Add(priority, new List<PowerConsumerComponent>());
|
||||||
|
_drawByPriority.Add(priority, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region BaseNodeGroup Overrides
|
||||||
|
|
||||||
|
protected override void SetNetConnectorNet(BasePowerNetComponent netConnectorComponent)
|
||||||
|
{
|
||||||
|
netConnectorComponent.Net = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BeforeCombine()
|
||||||
|
{
|
||||||
|
_supressPowerRecalculation = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AfterCombine()
|
||||||
|
{
|
||||||
|
_supressPowerRecalculation = false;
|
||||||
|
UpdateConsumerReceivedPower();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void BeforeRemake()
|
||||||
|
{
|
||||||
|
_supressPowerRecalculation = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void BeforeRemakeSpread()
|
||||||
|
{
|
||||||
|
_supressPowerRecalculation = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void AfterRemakeSpread()
|
||||||
|
{
|
||||||
|
_supressPowerRecalculation = false;
|
||||||
|
UpdateConsumerReceivedPower();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IPowerNet Methods
|
||||||
|
|
||||||
|
public void AddSupplier(PowerSupplierComponent supplier)
|
||||||
|
{
|
||||||
|
_suppliers.Add(supplier);
|
||||||
|
_totalSupply += supplier.SupplyRate;
|
||||||
|
UpdateConsumerReceivedPower();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveSupplier(PowerSupplierComponent supplier)
|
||||||
|
{
|
||||||
|
Debug.Assert(_suppliers.Contains(supplier));
|
||||||
|
_suppliers.Remove(supplier);
|
||||||
|
_totalSupply -= supplier.SupplyRate;
|
||||||
|
UpdateConsumerReceivedPower();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateSupplierSupply(PowerSupplierComponent supplier, int oldSupplyRate, int newSupplyRate)
|
||||||
|
{
|
||||||
|
Debug.Assert(_suppliers.Contains(supplier));
|
||||||
|
_totalSupply -= oldSupplyRate;
|
||||||
|
_totalSupply += newSupplyRate;
|
||||||
|
UpdateConsumerReceivedPower();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddConsumer(PowerConsumerComponent consumer)
|
||||||
|
{
|
||||||
|
_consumersByPriority[consumer.Priority].Add(consumer);
|
||||||
|
_drawByPriority[consumer.Priority] += consumer.DrawRate;
|
||||||
|
UpdateConsumerReceivedPower();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveConsumer(PowerConsumerComponent consumer)
|
||||||
|
{
|
||||||
|
Debug.Assert(_consumersByPriority[consumer.Priority].Contains(consumer));
|
||||||
|
_consumersByPriority[consumer.Priority].Add(consumer);
|
||||||
|
_drawByPriority[consumer.Priority] -= consumer.DrawRate;
|
||||||
|
UpdateConsumerReceivedPower();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateConsumerDraw(PowerConsumerComponent consumer, int oldDrawRate, int newDrawRate)
|
||||||
|
{
|
||||||
|
Debug.Assert(_consumersByPriority[consumer.Priority].Contains(consumer));
|
||||||
|
_drawByPriority[consumer.Priority] -= oldDrawRate;
|
||||||
|
_drawByPriority[consumer.Priority] += newDrawRate;
|
||||||
|
UpdateConsumerReceivedPower();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateConsumerPriority(PowerConsumerComponent consumer, Priority oldPriority, Priority newPriority)
|
||||||
|
{
|
||||||
|
Debug.Assert(_consumersByPriority[oldPriority].Contains(consumer));
|
||||||
|
_consumersByPriority[oldPriority].Remove(consumer);
|
||||||
|
_drawByPriority[oldPriority] -= consumer.DrawRate;
|
||||||
|
_consumersByPriority[newPriority].Add(consumer);
|
||||||
|
_drawByPriority[newPriority] += consumer.DrawRate;
|
||||||
|
UpdateConsumerReceivedPower();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateConsumerReceivedPower()
|
||||||
|
{
|
||||||
|
if (_supressPowerRecalculation)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var remainingSupply = _totalSupply;
|
||||||
|
foreach (Priority priority in Enum.GetValues(typeof(Priority)))
|
||||||
|
{
|
||||||
|
var categoryPowerDemand = _drawByPriority[priority];
|
||||||
|
if (remainingSupply - categoryPowerDemand >= 0) //can fully power all in category
|
||||||
|
{
|
||||||
|
remainingSupply -= categoryPowerDemand;
|
||||||
|
foreach (var consumer in _consumersByPriority[priority])
|
||||||
|
{
|
||||||
|
consumer.ReceivedPower = consumer.DrawRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (remainingSupply - categoryPowerDemand < 0) //cannot fully power all, split power
|
||||||
|
{
|
||||||
|
var availiablePowerFraction = (float) remainingSupply / categoryPowerDemand;
|
||||||
|
remainingSupply = 0;
|
||||||
|
foreach (var consumer in _consumersByPriority[priority])
|
||||||
|
{
|
||||||
|
consumer.ReceivedPower = (int) (consumer.DrawRate * availiablePowerFraction); //give each consumer a fraction of what they requested (rounded down to nearest int)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private class NullPowerNet : IPowerNet
|
||||||
|
{
|
||||||
|
public void AddConsumer(PowerConsumerComponent consumer) { }
|
||||||
|
public void AddSupplier(PowerSupplierComponent supplier) { }
|
||||||
|
public void UpdateSupplierSupply(PowerSupplierComponent supplier, int oldSupplyRate, int newSupplyRate) { }
|
||||||
|
public void RemoveConsumer(PowerConsumerComponent consumer) { }
|
||||||
|
public void RemoveSupplier(PowerSupplierComponent supplier) { }
|
||||||
|
public void UpdateConsumerDraw(PowerConsumerComponent consumer, int oldDrawRate, int newDrawRate) { }
|
||||||
|
public void UpdateConsumerPriority(PowerConsumerComponent consumer, Priority oldPriority, Priority newPriority) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
|
using Robust.Shared.GameObjects.Components.Transform;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.NodeContainer.Nodes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A <see cref="Node"/> that can reach other <see cref="AdjacentNode"/>s that are directly adjacent to it.
|
||||||
|
/// </summary>
|
||||||
|
[Node("AdjacentNode")]
|
||||||
|
public class AdjacentNode : Node
|
||||||
|
{
|
||||||
|
protected override IEnumerable<Node> GetReachableNodes()
|
||||||
|
{
|
||||||
|
return Owner.GetComponent<SnapGridComponent>()
|
||||||
|
.GetCardinalNeighborCells()
|
||||||
|
.SelectMany(sgc => sgc.GetLocal())
|
||||||
|
.Select(entity => entity.TryGetComponent<NodeContainerComponent>(out var container) ? container : null)
|
||||||
|
.Where(container => container != null)
|
||||||
|
.SelectMany(container => container.Nodes)
|
||||||
|
.Where(node => node != null && node != this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.NodeContainer.Nodes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Organizes themselves into distinct <see cref="INodeGroup"/>s with other <see cref="Node"/>s
|
||||||
|
/// that they can "reach" and have the same <see cref="Node.NodeGroupID"/>.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class Node
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An ID used as a criteria for combining into groups. Determines which <see cref="INodeGroup"/>
|
||||||
|
/// implementation is used as a group, detailed in <see cref="INodeGroupFactory"/>.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public NodeGroupID NodeGroupID { get; private set; }
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public INodeGroup NodeGroup { get => _nodeGroup; set => SetNodeGroup(value); }
|
||||||
|
private INodeGroup _nodeGroup = BaseNodeGroup.NullGroup;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public IEntity Owner { get; private set; }
|
||||||
|
|
||||||
|
private bool _needsGroup = true;
|
||||||
|
|
||||||
|
private bool _deleting = false;
|
||||||
|
|
||||||
|
|
||||||
|
#pragma warning disable 649
|
||||||
|
[Dependency] private readonly INodeGroupFactory _nodeGroupFactory;
|
||||||
|
#pragma warning restore 649
|
||||||
|
|
||||||
|
public void Initialize(NodeGroupID nodeGroupID, IEntity owner)
|
||||||
|
{
|
||||||
|
NodeGroupID = nodeGroupID;
|
||||||
|
Owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnContainerInitialize()
|
||||||
|
{
|
||||||
|
TryAssignGroupIfNeeded();
|
||||||
|
CombineGroupWithReachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnContainerRemove()
|
||||||
|
{
|
||||||
|
_deleting = true;
|
||||||
|
NodeGroup.RemoveNode(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryAssignGroupIfNeeded()
|
||||||
|
{
|
||||||
|
if (!_needsGroup)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
NodeGroup = GetReachableCompatibleGroups().FirstOrDefault() ?? MakeNewGroup();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartSpreadingGroup()
|
||||||
|
{
|
||||||
|
NodeGroup.BeforeRemakeSpread();
|
||||||
|
SpreadGroup();
|
||||||
|
NodeGroup.AfterRemakeSpread();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SpreadGroup()
|
||||||
|
{
|
||||||
|
Debug.Assert(!_needsGroup);
|
||||||
|
foreach (var node in GetReachableCompatibleNodes().Where(node => node._needsGroup == true))
|
||||||
|
{
|
||||||
|
node.NodeGroup = NodeGroup;
|
||||||
|
node.SpreadGroup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearNodeGroup()
|
||||||
|
{
|
||||||
|
_nodeGroup = BaseNodeGroup.NullGroup;
|
||||||
|
_needsGroup = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How this node will attempt to find other reachable <see cref="Node"/>s to group with.
|
||||||
|
/// Returns a set of <see cref="Node"/>s to consider grouping with. Should not return this current <see cref="Node"/>.
|
||||||
|
/// </summary>
|
||||||
|
protected abstract IEnumerable<Node> GetReachableNodes();
|
||||||
|
|
||||||
|
private IEnumerable<Node> GetReachableCompatibleNodes()
|
||||||
|
{
|
||||||
|
return GetReachableNodes().Where(node => node.NodeGroupID == NodeGroupID)
|
||||||
|
.Where(node => node._deleting == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<INodeGroup> GetReachableCompatibleGroups()
|
||||||
|
{
|
||||||
|
return GetReachableCompatibleNodes().Where(node => node._needsGroup == false)
|
||||||
|
.Select(node => node.NodeGroup)
|
||||||
|
.Where(group => group != NodeGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CombineGroupWithReachable()
|
||||||
|
{
|
||||||
|
Debug.Assert(!_needsGroup);
|
||||||
|
foreach (var group in GetReachableCompatibleGroups())
|
||||||
|
{
|
||||||
|
NodeGroup.CombineGroup(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetNodeGroup(INodeGroup newGroup)
|
||||||
|
{
|
||||||
|
_nodeGroup = newGroup;
|
||||||
|
NodeGroup.AddNode(this);
|
||||||
|
_needsGroup = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private INodeGroup MakeNewGroup()
|
||||||
|
{
|
||||||
|
return _nodeGroupFactory.MakeNodeGroup(NodeGroupID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.NodeContainer.Nodes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Associates a <see cref="Node"/> implementation with a string. This is used
|
||||||
|
/// to specify an <see cref="Node"/>'s strategy in yaml. Used by <see cref="INodeFactory"/>.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||||
|
public class
|
||||||
|
NodeAttribute : Attribute
|
||||||
|
{
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
public NodeAttribute(string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
|
using Robust.Shared.Interfaces.Reflection;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.NodeContainer.Nodes
|
||||||
|
{
|
||||||
|
public interface INodeFactory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Performs reflection to associate <see cref="Node"/> implementations with the
|
||||||
|
/// string specified in their <see cref="NodeAttribute"/>.
|
||||||
|
/// </summary>
|
||||||
|
void Initialize();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a new <see cref="Node"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
Node MakeNode(string nodeName, NodeGroupID groupID, IEntity owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NodeFactory : INodeFactory
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, Type> _groupTypes = new Dictionary<string, Type>();
|
||||||
|
|
||||||
|
#pragma warning disable 649
|
||||||
|
[Dependency] private readonly IReflectionManager _reflectionManager;
|
||||||
|
[Dependency] private readonly IDynamicTypeFactory _typeFactory;
|
||||||
|
#pragma warning restore 649
|
||||||
|
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
var nodeTypes = _reflectionManager.GetAllChildren<Node>();
|
||||||
|
foreach (var nodeType in nodeTypes)
|
||||||
|
{
|
||||||
|
var att = nodeType.GetCustomAttribute<NodeAttribute>();
|
||||||
|
if (att != null)
|
||||||
|
{
|
||||||
|
_groupTypes.Add(att.Name, nodeType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Node MakeNode(string nodeName, NodeGroupID groupID, IEntity owner)
|
||||||
|
{
|
||||||
|
if (_groupTypes.TryGetValue(nodeName, out var type))
|
||||||
|
{
|
||||||
|
var newNode = _typeFactory.CreateInstance<Node>(type);
|
||||||
|
newNode.Initialize(groupID, owner);
|
||||||
|
return newNode;
|
||||||
|
}
|
||||||
|
throw new ArgumentException($"{nodeName} did not have an associated {nameof(Node)}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
using Content.Server.GameObjects.EntitySystems;
|
|
||||||
using Content.Shared.GameObjects.Components.Power;
|
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Server.GameObjects.Components.UserInterface;
|
|
||||||
using Robust.Server.GameObjects.EntitySystems;
|
|
||||||
using Robust.Server.Interfaces.GameObjects;
|
|
||||||
using Robust.Shared.Audio;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.GameObjects.Systems;
|
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Power
|
|
||||||
{
|
|
||||||
[RegisterComponent]
|
|
||||||
[ComponentReference(typeof(IActivate))]
|
|
||||||
public sealed class ApcComponent : SharedApcComponent, IActivate
|
|
||||||
{
|
|
||||||
PowerStorageComponent Storage;
|
|
||||||
AppearanceComponent Appearance;
|
|
||||||
private PowerProviderComponent _provider;
|
|
||||||
|
|
||||||
ApcChargeState LastChargeState;
|
|
||||||
private float _lastCharge = 0f;
|
|
||||||
private ApcExternalPowerState _lastExternalPowerState;
|
|
||||||
private BoundUserInterface _userInterface;
|
|
||||||
private bool _uiDirty = true;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
Storage = Owner.GetComponent<PowerStorageComponent>();
|
|
||||||
Appearance = Owner.GetComponent<AppearanceComponent>();
|
|
||||||
_provider = Owner.GetComponent<PowerProviderComponent>();
|
|
||||||
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(ApcUiKey.Key);
|
|
||||||
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg)
|
|
||||||
{
|
|
||||||
var obj = serverMsg.Message;
|
|
||||||
if (obj is ApcToggleMainBreakerMessage)
|
|
||||||
{
|
|
||||||
_provider.MainBreaker = !_provider.MainBreaker;
|
|
||||||
_uiDirty = true;
|
|
||||||
_clickSound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnUpdate()
|
|
||||||
{
|
|
||||||
var newState = CalcChargeState();
|
|
||||||
if (newState != LastChargeState)
|
|
||||||
{
|
|
||||||
LastChargeState = newState;
|
|
||||||
Appearance.SetData(ApcVisuals.ChargeState, newState);
|
|
||||||
}
|
|
||||||
|
|
||||||
var newCharge = Storage.Charge;
|
|
||||||
if (newCharge != _lastCharge)
|
|
||||||
{
|
|
||||||
_lastCharge = newCharge;
|
|
||||||
_uiDirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var extPowerState = CalcExtPowerState();
|
|
||||||
if (extPowerState != _lastExternalPowerState)
|
|
||||||
{
|
|
||||||
_lastExternalPowerState = extPowerState;
|
|
||||||
_uiDirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_uiDirty)
|
|
||||||
{
|
|
||||||
_userInterface.SetState(new ApcBoundInterfaceState(_provider.MainBreaker, extPowerState,
|
|
||||||
newCharge / Storage.Capacity));
|
|
||||||
_uiDirty = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ApcChargeState CalcChargeState()
|
|
||||||
{
|
|
||||||
var storageCharge = Storage.GetChargeState();
|
|
||||||
switch (storageCharge)
|
|
||||||
{
|
|
||||||
case ChargeState.Discharging:
|
|
||||||
return ApcChargeState.Lack;
|
|
||||||
case ChargeState.Charging:
|
|
||||||
return ApcChargeState.Charging;
|
|
||||||
default:
|
|
||||||
// Still.
|
|
||||||
return Storage.Full ? ApcChargeState.Full : ApcChargeState.Lack;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ApcExternalPowerState CalcExtPowerState()
|
|
||||||
{
|
|
||||||
if (!Owner.TryGetComponent(out PowerNodeComponent node) || node.Parent == null)
|
|
||||||
{
|
|
||||||
return ApcExternalPowerState.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
var net = node.Parent;
|
|
||||||
if (net.LastTotalAvailable <= 0)
|
|
||||||
{
|
|
||||||
return ApcExternalPowerState.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
return net.Lack > 0 ? ApcExternalPowerState.Low : ApcExternalPowerState.Good;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IActivate.Activate(ActivateEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
if (!eventArgs.User.TryGetComponent(out IActorComponent actor))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_userInterface.Open(actor.playerSession);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void _clickSound()
|
|
||||||
{
|
|
||||||
EntitySystem.Get<AudioSystem>().PlayFromEntity("/Audio/machines/machine_switch.ogg", Owner,AudioParams.Default.WithVolume(-2f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
using Content.Server.GameObjects.Components.Power.PowerNetComponents;
|
||||||
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
|
using Content.Shared.GameObjects.Components.Power;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Server.GameObjects.Components.UserInterface;
|
||||||
|
using Robust.Server.GameObjects.EntitySystems;
|
||||||
|
using Robust.Server.Interfaces.GameObjects;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects.Systems;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
using System;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Interfaces.Timing;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
[ComponentReference(typeof(IActivate))]
|
||||||
|
public class ApcComponent : BaseApcNetComponent, IActivate
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
private ApcExternalPowerState _lastExternalPowerState;
|
||||||
|
|
||||||
|
private TimeSpan _lastExternalPowerStateChange;
|
||||||
|
|
||||||
|
private float _lastCharge = 0f;
|
||||||
|
|
||||||
|
private bool _uiDirty = true;
|
||||||
|
|
||||||
|
private const float HighPowerThreshold = 0.9f;
|
||||||
|
|
||||||
|
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>();
|
||||||
|
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(ApcUiKey.Key);
|
||||||
|
_userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void AddSelfToNet(IApcNet apcNet)
|
||||||
|
{
|
||||||
|
apcNet.AddApc(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void RemoveSelfFromNet(IApcNet apcNet)
|
||||||
|
{
|
||||||
|
apcNet.RemoveApc(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg)
|
||||||
|
{
|
||||||
|
if (serverMsg.Message is ApcToggleMainBreakerMessage)
|
||||||
|
{
|
||||||
|
MainBreakerEnabled = !MainBreakerEnabled;
|
||||||
|
_uiDirty = true;
|
||||||
|
EntitySystem.Get<AudioSystem>().PlayFromEntity("/Audio/machines/machine_switch.ogg", Owner, AudioParams.Default.WithVolume(-2f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
var newState = CalcChargeState();
|
||||||
|
if (newState != _lastChargeState && _lastChargeStateChange + TimeSpan.FromSeconds(VisualsChangeDelay) < _gameTiming.CurTime)
|
||||||
|
{
|
||||||
|
_lastChargeState = newState;
|
||||||
|
_lastChargeStateChange = _gameTiming.CurTime;
|
||||||
|
_appearance.SetData(ApcVisuals.ChargeState, newState);
|
||||||
|
}
|
||||||
|
var newCharge = Battery.CurrentCharge;
|
||||||
|
if (newCharge != _lastCharge)
|
||||||
|
{
|
||||||
|
_lastCharge = newCharge;
|
||||||
|
_uiDirty = true;
|
||||||
|
}
|
||||||
|
var extPowerState = CalcExtPowerState();
|
||||||
|
if (extPowerState != _lastExternalPowerState && _lastExternalPowerStateChange + TimeSpan.FromSeconds(VisualsChangeDelay) < _gameTiming.CurTime)
|
||||||
|
{
|
||||||
|
_lastExternalPowerState = extPowerState;
|
||||||
|
_lastExternalPowerStateChange = _gameTiming.CurTime;
|
||||||
|
_uiDirty = true;
|
||||||
|
}
|
||||||
|
if (_uiDirty)
|
||||||
|
{
|
||||||
|
_userInterface.SetState(new ApcBoundInterfaceState(MainBreakerEnabled, extPowerState, newCharge / Battery.MaxCharge));
|
||||||
|
_uiDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ApcChargeState CalcChargeState()
|
||||||
|
{
|
||||||
|
var chargeFraction = Battery.CurrentCharge / Battery.MaxCharge;
|
||||||
|
if (chargeFraction > HighPowerThreshold)
|
||||||
|
{
|
||||||
|
return ApcChargeState.Full;
|
||||||
|
}
|
||||||
|
var consumer = Owner.GetComponent<PowerConsumerComponent>();
|
||||||
|
if (consumer.DrawRate == consumer.ReceivedPower)
|
||||||
|
{
|
||||||
|
return ApcChargeState.Charging;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ApcChargeState.Lack;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ApcExternalPowerState CalcExtPowerState()
|
||||||
|
{
|
||||||
|
if (!Owner.TryGetComponent(out BatteryStorageComponent batteryStorage))
|
||||||
|
{
|
||||||
|
return ApcExternalPowerState.None;
|
||||||
|
}
|
||||||
|
var consumer = batteryStorage.Consumer;
|
||||||
|
if (consumer.ReceivedPower == 0 && consumer.DrawRate != 0)
|
||||||
|
{
|
||||||
|
return ApcExternalPowerState.None;
|
||||||
|
}
|
||||||
|
else if (consumer.ReceivedPower < consumer.DrawRate)
|
||||||
|
{
|
||||||
|
return ApcExternalPowerState.Low;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ApcExternalPowerState.Good;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IActivate.Activate(ActivateEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
if (!eventArgs.User.TryGetComponent(out IActorComponent actor))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_userInterface.Open(actor.playerSession);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
|
||||||
|
{
|
||||||
|
public abstract class BaseApcNetComponent : BaseNetConnectorComponent<IApcNet>
|
||||||
|
{
|
||||||
|
protected override IApcNet NullNet => ApcNetNodeGroup.NullNet;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
|
using Robust.Server.Interfaces.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Interfaces.Map;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Power.ApcNetComponents
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Relays <see cref="PowerReceiverComponent"/>s in an area to a <see cref="IApcNet"/> so they can receive power.
|
||||||
|
/// </summary>
|
||||||
|
public interface IPowerProvider
|
||||||
|
{
|
||||||
|
void AddReceiver(PowerReceiverComponent receiver);
|
||||||
|
|
||||||
|
void RemoveReceiver(PowerReceiverComponent receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
public class PowerProviderComponent : BaseApcNetComponent, IPowerProvider
|
||||||
|
{
|
||||||
|
public override string Name => "PowerProvider";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The max distance this can transmit power to <see cref="PowerReceiverComponent"/>s from.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public int PowerTransferRange { get => _powerTransferRange; set => SetPowerTransferRange(value); }
|
||||||
|
private int _powerTransferRange;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public IReadOnlyList<PowerReceiverComponent> LinkedReceivers => _linkedReceivers;
|
||||||
|
private List<PowerReceiverComponent> _linkedReceivers = new List<PowerReceiverComponent>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If <see cref="PowerReceiverComponent"/>s should consider connecting to this.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public bool Connectable { get; private set; } = true;
|
||||||
|
|
||||||
|
public static readonly IPowerProvider NullProvider = new NullPowerProvider();
|
||||||
|
|
||||||
|
public void AddReceiver(PowerReceiverComponent receiver)
|
||||||
|
{
|
||||||
|
_linkedReceivers.Add(receiver);
|
||||||
|
Net.UpdatePowerProviderReceivers(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveReceiver(PowerReceiverComponent receiver)
|
||||||
|
{
|
||||||
|
_linkedReceivers.Remove(receiver);
|
||||||
|
Net.UpdatePowerProviderReceivers(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
|
{
|
||||||
|
base.ExposeData(serializer);
|
||||||
|
serializer.DataField(ref _powerTransferRange, "powerTransferRange", 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Startup()
|
||||||
|
{
|
||||||
|
base.Startup();
|
||||||
|
foreach (var receiver in FindAvailableReceivers())
|
||||||
|
{
|
||||||
|
receiver.Provider = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnRemove()
|
||||||
|
{
|
||||||
|
Connectable = false;
|
||||||
|
var receivers = _linkedReceivers.ToArray();
|
||||||
|
foreach (var receiver in receivers)
|
||||||
|
{
|
||||||
|
receiver.ClearProvider();
|
||||||
|
}
|
||||||
|
_linkedReceivers = new List<PowerReceiverComponent>();
|
||||||
|
Net.UpdatePowerProviderReceivers(this);
|
||||||
|
foreach (var receiver in receivers)
|
||||||
|
{
|
||||||
|
receiver.TryFindAndSetProvider();
|
||||||
|
}
|
||||||
|
base.OnRemove();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<PowerReceiverComponent> FindAvailableReceivers()
|
||||||
|
{
|
||||||
|
var mapManager = IoCManager.Resolve<IMapManager>();
|
||||||
|
var nearbyEntities = IoCManager.Resolve<IServerEntityManager>()
|
||||||
|
.GetEntitiesInRange(Owner, PowerTransferRange);
|
||||||
|
return nearbyEntities.Select(entity => entity.TryGetComponent<PowerReceiverComponent>(out var receiver) ? receiver : null)
|
||||||
|
.Where(receiver => receiver != null)
|
||||||
|
.Where(receiver => receiver.NeedsProvider)
|
||||||
|
.Where(receiver => receiver.Owner.Transform.GridPosition.Distance(mapManager, Owner.Transform.GridPosition) < Math.Min(PowerTransferRange, receiver.PowerReceptionRange))
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void AddSelfToNet(IApcNet apcNet)
|
||||||
|
{
|
||||||
|
apcNet.AddPowerProvider(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void RemoveSelfFromNet(IApcNet apcNet)
|
||||||
|
{
|
||||||
|
apcNet.RemovePowerProvider(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetPowerTransferRange(int newPowerTransferRange)
|
||||||
|
{
|
||||||
|
foreach (var receiver in _linkedReceivers)
|
||||||
|
{
|
||||||
|
receiver.ClearProvider();
|
||||||
|
}
|
||||||
|
_powerTransferRange = newPowerTransferRange;
|
||||||
|
_linkedReceivers = FindAvailableReceivers();
|
||||||
|
Net.UpdatePowerProviderReceivers(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class NullPowerProvider : IPowerProvider
|
||||||
|
{
|
||||||
|
public void AddReceiver(PowerReceiverComponent receiver) { }
|
||||||
|
public void RemoveReceiver(PowerReceiverComponent receiver) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,198 @@
|
|||||||
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
|
using Content.Shared.GameObjects.Components.Power;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Server.Interfaces.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Interfaces.Map;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public bool NeedsProvider { get; private set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Amount of charge this needs from an APC per second to function.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public int Load { get => _load; set => SetLoad(value); }
|
||||||
|
private int _load;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When true, 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>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnRemove()
|
||||||
|
{
|
||||||
|
_provider.RemoveReceiver(this);
|
||||||
|
base.OnRemove();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TryFindAndSetProvider()
|
||||||
|
{
|
||||||
|
if (TryFindAvailableProvider(out var provider))
|
||||||
|
{
|
||||||
|
Provider = provider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryFindAvailableProvider(out IPowerProvider foundProvider)
|
||||||
|
{
|
||||||
|
var nearbyEntities = IoCManager.Resolve<IServerEntityManager>()
|
||||||
|
.GetEntitiesInRange(Owner, PowerReceptionRange);
|
||||||
|
var mapManager = IoCManager.Resolve<IMapManager>();
|
||||||
|
foreach (var entity in nearbyEntities)
|
||||||
|
{
|
||||||
|
if (entity.TryGetComponent<PowerProviderComponent>(out var provider))
|
||||||
|
{
|
||||||
|
if (provider.Connectable)
|
||||||
|
{
|
||||||
|
var distanceToProvider = provider.Owner.Transform.GridPosition.Distance(mapManager, Owner.Transform.GridPosition);
|
||||||
|
if (distanceToProvider < 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(out AppearanceComponent appearance))
|
||||||
|
{
|
||||||
|
appearance.SetData(PowerDeviceVisuals.Powered, Powered);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PowerStateEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public readonly bool Powered;
|
||||||
|
|
||||||
|
public PowerStateEventArgs(bool powered)
|
||||||
|
{
|
||||||
|
Powered = powered;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,282 @@
|
|||||||
|
using System;
|
||||||
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
|
using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels;
|
||||||
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
|
using Content.Shared.GameObjects;
|
||||||
|
using Content.Shared.GameObjects.Components.Power;
|
||||||
|
using Content.Shared.GameObjects.EntitySystems;
|
||||||
|
using Content.Shared.Interfaces;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Server.GameObjects.Components.Container;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Power.Chargers
|
||||||
|
{
|
||||||
|
[ComponentReference(typeof(IActivate))]
|
||||||
|
[ComponentReference(typeof(IInteractUsing))]
|
||||||
|
public abstract class BaseCharger : Component, IActivate, IInteractUsing
|
||||||
|
{
|
||||||
|
[ViewVariables]
|
||||||
|
private BatteryComponent _heldBattery;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private ContainerSlot _container;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private PowerReceiverComponent _powerReceiver;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private CellChargerStatus _status;
|
||||||
|
|
||||||
|
private AppearanceComponent _appearanceComponent;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private int _chargeRate;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private float _transferEfficiency;
|
||||||
|
|
||||||
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
|
{
|
||||||
|
base.ExposeData(serializer);
|
||||||
|
serializer.DataField(ref _chargeRate, "chargeRate", 100);
|
||||||
|
serializer.DataField(ref _transferEfficiency, "transferEfficiency", 0.85f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
_powerReceiver = Owner.GetComponent<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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnRemove()
|
||||||
|
{
|
||||||
|
_powerReceiver.OnPowerStateChanged -= PowerUpdate;
|
||||||
|
base.OnRemove();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
var result = TryInsertItem(eventArgs.Using);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
var localizationManager = IoCManager.Resolve<ILocalizationManager>();
|
||||||
|
eventArgs.User.PopupMessage(Owner, localizationManager.GetString("Unable to insert capacitor"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IActivate.Activate(ActivateEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
RemoveItem(eventArgs.User);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This will remove the item directly into the user's hand / floor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="user"></param>
|
||||||
|
private void RemoveItem(IEntity user)
|
||||||
|
{
|
||||||
|
var heldItem = _container.ContainedEntity;
|
||||||
|
if (heldItem == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_container.Remove(heldItem);
|
||||||
|
_heldBattery = null;
|
||||||
|
if (user.TryGetComponent(out HandsComponent handsComponent))
|
||||||
|
{
|
||||||
|
handsComponent.PutInHandOrDrop(heldItem.GetComponent<ItemComponent>());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heldItem.TryGetComponent(out ServerBatteryBarrelComponent batteryBarrelComponent))
|
||||||
|
{
|
||||||
|
batteryBarrelComponent.UpdateAppearance();
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PowerUpdate(object sender, PowerStateEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Verb]
|
||||||
|
private sealed class InsertVerb : Verb<BaseCharger>
|
||||||
|
{
|
||||||
|
protected override void GetData(IEntity user, BaseCharger component, VerbData data)
|
||||||
|
{
|
||||||
|
if (!ActionBlockerSystem.CanInteract(user))
|
||||||
|
{
|
||||||
|
data.Visibility = VerbVisibility.Invisible;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!user.TryGetComponent(out HandsComponent handsComponent))
|
||||||
|
{
|
||||||
|
data.Visibility = VerbVisibility.Invisible;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component._container.ContainedEntity != null || handsComponent.GetActiveHand == null)
|
||||||
|
{
|
||||||
|
data.Visibility = VerbVisibility.Disabled;
|
||||||
|
data.Text = "Insert";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.Text = $"Insert {handsComponent.GetActiveHand.Owner.Name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Activate(IEntity user, BaseCharger component)
|
||||||
|
{
|
||||||
|
if (!user.TryGetComponent(out HandsComponent handsComponent))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handsComponent.GetActiveHand == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var userItem = handsComponent.GetActiveHand.Owner;
|
||||||
|
handsComponent.Drop(userItem);
|
||||||
|
component.TryInsertItem(userItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Verb]
|
||||||
|
private sealed class EjectVerb : Verb<BaseCharger>
|
||||||
|
{
|
||||||
|
protected override void GetData(IEntity user, BaseCharger component, VerbData data)
|
||||||
|
{
|
||||||
|
if (!ActionBlockerSystem.CanInteract(user))
|
||||||
|
{
|
||||||
|
data.Visibility = VerbVisibility.Invisible;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (component._container.ContainedEntity == null)
|
||||||
|
{
|
||||||
|
data.Text = "Eject";
|
||||||
|
data.Visibility = VerbVisibility.Disabled;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.Text = $"Eject {component._container.ContainedEntity.Name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Activate(IEntity user, BaseCharger component)
|
||||||
|
{
|
||||||
|
component.RemoveItem(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CellChargerStatus GetStatus()
|
||||||
|
{
|
||||||
|
if (!_powerReceiver.Powered)
|
||||||
|
{
|
||||||
|
return CellChargerStatus.Off;
|
||||||
|
}
|
||||||
|
if (_container.ContainedEntity == null)
|
||||||
|
{
|
||||||
|
return CellChargerStatus.Empty;
|
||||||
|
}
|
||||||
|
if (_heldBattery != null && Math.Abs(_heldBattery.MaxCharge - _heldBattery.CurrentCharge) < 0.01)
|
||||||
|
{
|
||||||
|
return CellChargerStatus.Charged;
|
||||||
|
}
|
||||||
|
return CellChargerStatus.Charging;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryInsertItem(IEntity entity)
|
||||||
|
{
|
||||||
|
if (!IsEntityCompatible(entity) || _container.ContainedEntity != null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!_container.Insert(entity))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_heldBattery = GetBatteryFrom(entity);
|
||||||
|
UpdateStatus();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If the supplied entity should fit into the charger.
|
||||||
|
/// </summary>
|
||||||
|
protected abstract bool IsEntityCompatible(IEntity entity);
|
||||||
|
|
||||||
|
protected abstract BatteryComponent GetBatteryFrom(IEntity entity);
|
||||||
|
|
||||||
|
private void UpdateStatus()
|
||||||
|
{
|
||||||
|
// Not called UpdateAppearance just because it messes with the load
|
||||||
|
var status = GetStatus();
|
||||||
|
if (_status == status)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_status = status;
|
||||||
|
switch (_status)
|
||||||
|
{
|
||||||
|
// Update load just in case
|
||||||
|
case CellChargerStatus.Off:
|
||||||
|
_powerReceiver.Load = 0;
|
||||||
|
_appearanceComponent?.SetData(CellVisual.Light, CellChargerStatus.Off);
|
||||||
|
break;
|
||||||
|
case CellChargerStatus.Empty:
|
||||||
|
_powerReceiver.Load = 0;
|
||||||
|
_appearanceComponent?.SetData(CellVisual.Light, CellChargerStatus.Empty); ;
|
||||||
|
break;
|
||||||
|
case CellChargerStatus.Charging:
|
||||||
|
_powerReceiver.Load = (int) (_chargeRate / _transferEfficiency);
|
||||||
|
_appearanceComponent?.SetData(CellVisual.Light, CellChargerStatus.Charging);
|
||||||
|
break;
|
||||||
|
case CellChargerStatus.Charged:
|
||||||
|
_powerReceiver.Load = 0;
|
||||||
|
_appearanceComponent?.SetData(CellVisual.Light, CellChargerStatus.Charged);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
_appearanceComponent?.SetData(CellVisual.Occupied, _container.ContainedEntity != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnUpdate(float frameTime) //todo: make single system for this
|
||||||
|
{
|
||||||
|
if (_status == CellChargerStatus.Empty || _status == CellChargerStatus.Charged || _container.ContainedEntity == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TransferPower(frameTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TransferPower(float frameTime)
|
||||||
|
{
|
||||||
|
if (!_powerReceiver.Powered)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_heldBattery.CurrentCharge += _chargeRate * frameTime;
|
||||||
|
// Just so the sprite won't be set to 99.99999% visibility
|
||||||
|
if (_heldBattery.MaxCharge - _heldBattery.CurrentCharge < 0.01)
|
||||||
|
{
|
||||||
|
_heldBattery.CurrentCharge = _heldBattery.MaxCharge;
|
||||||
|
}
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -68,8 +68,8 @@ namespace Content.Server.GameObjects.Components.Power
|
|||||||
private int _burningTemperature;
|
private int _burningTemperature;
|
||||||
public int BurningTemperature => _burningTemperature;
|
public int BurningTemperature => _burningTemperature;
|
||||||
|
|
||||||
private float _powerUse;
|
private int _powerUse;
|
||||||
public float PowerUse => _powerUse;
|
public int PowerUse => _powerUse;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current state of the light bulb. Invokes the OnLightBulbStateChange event when set.
|
/// The current state of the light bulb. Invokes the OnLightBulbStateChange event when set.
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Power.Chargers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Recharges an entity with a <see cref="BatteryComponent"/>.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
[ComponentReference(typeof(IActivate))]
|
||||||
|
[ComponentReference(typeof(BaseCharger))]
|
||||||
|
public sealed class PowerCellChargerComponent : BaseCharger
|
||||||
|
{
|
||||||
|
public override string Name => "PowerCellCharger";
|
||||||
|
|
||||||
|
protected override bool IsEntityCompatible(IEntity entity)
|
||||||
|
{
|
||||||
|
return entity.HasComponent<BatteryComponent>();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override BatteryComponent GetBatteryFrom(IEntity entity)
|
||||||
|
{
|
||||||
|
return entity.GetComponent<BatteryComponent>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
using Content.Server.GameObjects.Components.Sound;
|
using Content.Server.GameObjects.Components.Sound;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
using Content.Server.Utility;
|
using Content.Server.Utility;
|
||||||
@@ -148,12 +149,12 @@ namespace Content.Server.GameObjects.Components.Power
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void UpdateLight()
|
public void UpdateLight()
|
||||||
{
|
{
|
||||||
var device = Owner.GetComponent<PowerDeviceComponent>();
|
var powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
|
||||||
var sprite = Owner.GetComponent<SpriteComponent>();
|
var sprite = Owner.GetComponent<SpriteComponent>();
|
||||||
var light = Owner.GetComponent<PointLightComponent>();
|
var light = Owner.GetComponent<PointLightComponent>();
|
||||||
if (LightBulb == null) // No light bulb.
|
if (LightBulb == null) // No light bulb.
|
||||||
{
|
{
|
||||||
device.Load = 0;
|
powerReceiver.Load = 0;
|
||||||
sprite.LayerSetState(0, "empty");
|
sprite.LayerSetState(0, "empty");
|
||||||
light.Enabled = false;
|
light.Enabled = false;
|
||||||
return;
|
return;
|
||||||
@@ -162,8 +163,8 @@ namespace Content.Server.GameObjects.Components.Power
|
|||||||
switch (LightBulb.State)
|
switch (LightBulb.State)
|
||||||
{
|
{
|
||||||
case LightBulbState.Normal:
|
case LightBulbState.Normal:
|
||||||
device.Load = LightBulb.PowerUse;
|
powerReceiver.Load = LightBulb.PowerUse;
|
||||||
if (device.Powered)
|
if (powerReceiver.Powered)
|
||||||
{
|
{
|
||||||
sprite.LayerSetState(0, "on");
|
sprite.LayerSetState(0, "on");
|
||||||
light.Enabled = true;
|
light.Enabled = true;
|
||||||
@@ -182,12 +183,12 @@ namespace Content.Server.GameObjects.Components.Power
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LightBulbState.Broken:
|
case LightBulbState.Broken:
|
||||||
device.Load = 0;
|
powerReceiver.Load = 0;
|
||||||
sprite.LayerSetState(0, "broken");
|
sprite.LayerSetState(0, "broken");
|
||||||
light.Enabled = false;
|
light.Enabled = false;
|
||||||
break;
|
break;
|
||||||
case LightBulbState.Burned:
|
case LightBulbState.Burned:
|
||||||
device.Load = 0;
|
powerReceiver.Load = 0;
|
||||||
sprite.LayerSetState(0, "burned");
|
sprite.LayerSetState(0, "burned");
|
||||||
light.Enabled = false;
|
light.Enabled = false;
|
||||||
break;
|
break;
|
||||||
@@ -198,8 +199,7 @@ namespace Content.Server.GameObjects.Components.Power
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
var device = Owner.GetComponent<PowerDeviceComponent>();
|
Owner.GetComponent<PowerReceiverComponent>().OnPowerStateChanged += UpdateLight;
|
||||||
device.OnPowerStateChanged += UpdateLight;
|
|
||||||
|
|
||||||
_lightBulbContainer = ContainerManagerComponent.Ensure<ContainerSlot>("light_bulb", Owner, out var existed);
|
_lightBulbContainer = ContainerManagerComponent.Ensure<ContainerSlot>("light_bulb", Owner, out var existed);
|
||||||
|
|
||||||
@@ -216,5 +216,11 @@ namespace Content.Server.GameObjects.Components.Power
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OnRemove()
|
||||||
|
{
|
||||||
|
Owner.GetComponent<PowerReceiverComponent>().OnPowerStateChanged -= UpdateLight;
|
||||||
|
base.OnRemove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels;
|
||||||
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Power.Chargers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Recharges the battery in a <see cref="ServerBatteryBarrelComponent"/>.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
[ComponentReference(typeof(IActivate))]
|
||||||
|
[ComponentReference(typeof(BaseCharger))]
|
||||||
|
public sealed class WeaponCapacitorChargerComponent : BaseCharger
|
||||||
|
{
|
||||||
|
public override string Name => "WeaponCapacitorCharger";
|
||||||
|
|
||||||
|
protected override bool IsEntityCompatible(IEntity entity)
|
||||||
|
{
|
||||||
|
return entity.HasComponent<ServerBatteryBarrelComponent>();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override BatteryComponent GetBatteryFrom(IEntity entity)
|
||||||
|
{
|
||||||
|
return entity.GetComponent<ServerBatteryBarrelComponent>().PowerCell;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
using Content.Server.GameObjects.Components.NodeContainer;
|
||||||
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Power
|
||||||
|
{
|
||||||
|
public abstract class BaseNetConnectorComponent<TNetType> : Component
|
||||||
|
{
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public Voltage Voltage { get => _voltage; set => SetVoltage(value); }
|
||||||
|
private Voltage _voltage;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public TNetType Net { get => _net; set => SetNet(value); }
|
||||||
|
private TNetType _net;
|
||||||
|
|
||||||
|
protected abstract TNetType NullNet { get; }
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private bool _needsNet = true;
|
||||||
|
|
||||||
|
public override void OnAdd()
|
||||||
|
{
|
||||||
|
base.OnAdd();
|
||||||
|
_net = NullNet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
|
{
|
||||||
|
base.ExposeData(serializer);
|
||||||
|
serializer.DataField(ref _voltage, "voltage", Voltage.High);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
if (_needsNet)
|
||||||
|
{
|
||||||
|
TryFindAndSetNet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnRemove()
|
||||||
|
{
|
||||||
|
ClearNet();
|
||||||
|
base.OnRemove();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TryFindAndSetNet()
|
||||||
|
{
|
||||||
|
if (TryFindNet(out var net))
|
||||||
|
{
|
||||||
|
Net = net;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearNet()
|
||||||
|
{
|
||||||
|
RemoveSelfFromNet(_net);
|
||||||
|
_net = NullNet;
|
||||||
|
_needsNet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void AddSelfToNet(TNetType net);
|
||||||
|
|
||||||
|
protected abstract void RemoveSelfFromNet(TNetType net);
|
||||||
|
|
||||||
|
private bool TryFindNet(out TNetType foundNet)
|
||||||
|
{
|
||||||
|
if (Owner.TryGetComponent<NodeContainerComponent>(out var container))
|
||||||
|
{
|
||||||
|
var compatibleNet = container.Nodes
|
||||||
|
.Where(node => node.NodeGroupID == (NodeGroupID) Voltage)
|
||||||
|
.Select(node => node.NodeGroup)
|
||||||
|
.OfType<TNetType>()
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
if (compatibleNet != null)
|
||||||
|
{
|
||||||
|
foundNet = compatibleNet;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foundNet = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetNet(TNetType newNet)
|
||||||
|
{
|
||||||
|
RemoveSelfFromNet(_net);
|
||||||
|
AddSelfToNet(newNet);
|
||||||
|
_net = newNet;
|
||||||
|
_needsNet = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetVoltage(Voltage newVoltage)
|
||||||
|
{
|
||||||
|
ClearNet();
|
||||||
|
_voltage = newVoltage;
|
||||||
|
TryFindAndSetNet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Voltage
|
||||||
|
{
|
||||||
|
High = NodeGroupID.HVPower,
|
||||||
|
Medium = NodeGroupID.MVPower,
|
||||||
|
Apc = NodeGroupID.Apc,
|
||||||
|
}
|
||||||
|
}
|
||||||
115
Content.Server/GameObjects/Components/Power/BatteryComponent.cs
Normal file
115
Content.Server/GameObjects/Components/Power/BatteryComponent.cs
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Power
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
public class BatteryComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name => "Battery";
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public int MaxCharge { get => _maxCharge; set => SetMaxCharge(value); }
|
||||||
|
private int _maxCharge;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float CurrentCharge { get => _currentCharge; set => SetCurrentCharge(value); }
|
||||||
|
private float _currentCharge;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public BatteryState BatteryState { get; private set; }
|
||||||
|
|
||||||
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
|
{
|
||||||
|
base.ExposeData(serializer);
|
||||||
|
serializer.DataField(ref _maxCharge, "maxCharge", 1000);
|
||||||
|
serializer.DataField(ref _currentCharge, "startingCharge", 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
UpdateStorageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If sufficient charge is avaiable on the battery, use it. Otherwise, don't.
|
||||||
|
/// </summary>
|
||||||
|
public bool TryUseCharge(float chargeToUse)
|
||||||
|
{
|
||||||
|
if (chargeToUse >= CurrentCharge)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CurrentCharge -= chargeToUse;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float UseCharge(float toDeduct)
|
||||||
|
{
|
||||||
|
var chargeChangedBy = Math.Min(CurrentCharge, toDeduct);
|
||||||
|
CurrentCharge -= chargeChangedBy;
|
||||||
|
return chargeChangedBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FillFrom(BatteryComponent battery)
|
||||||
|
{
|
||||||
|
var powerDeficit = MaxCharge - CurrentCharge;
|
||||||
|
if (battery.TryUseCharge(powerDeficit))
|
||||||
|
{
|
||||||
|
CurrentCharge += powerDeficit;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CurrentCharge += battery.CurrentCharge;
|
||||||
|
battery.CurrentCharge = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnChargeChanged() { }
|
||||||
|
|
||||||
|
private void UpdateStorageState()
|
||||||
|
{
|
||||||
|
if (CurrentCharge == MaxCharge)
|
||||||
|
{
|
||||||
|
BatteryState = BatteryState.Full;
|
||||||
|
}
|
||||||
|
else if (CurrentCharge == 0)
|
||||||
|
{
|
||||||
|
BatteryState = BatteryState.Empty;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BatteryState = BatteryState.PartlyFull;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetMaxCharge(int newMax)
|
||||||
|
{
|
||||||
|
_maxCharge = Math.Max(newMax, 0);
|
||||||
|
_currentCharge = Math.Min( _currentCharge, MaxCharge);
|
||||||
|
UpdateStorageState();
|
||||||
|
OnChargeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetCurrentCharge(float newChargeAmount)
|
||||||
|
{
|
||||||
|
_currentCharge = FloatMath.Clamp(newChargeAmount, 0, MaxCharge);
|
||||||
|
UpdateStorageState();
|
||||||
|
OnChargeChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum BatteryState
|
||||||
|
{
|
||||||
|
Full,
|
||||||
|
PartlyFull,
|
||||||
|
Empty
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels;
|
|
||||||
using Content.Shared.GameObjects.Components.Power;
|
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Server.GameObjects.Components.Container;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Serialization;
|
|
||||||
using Robust.Shared.ViewVariables;
|
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Power.Chargers
|
|
||||||
{
|
|
||||||
public abstract class BaseCharger : Component
|
|
||||||
{
|
|
||||||
|
|
||||||
protected IEntity _heldItem;
|
|
||||||
protected ContainerSlot _container;
|
|
||||||
protected PowerDeviceComponent _powerDevice;
|
|
||||||
public CellChargerStatus Status => _status;
|
|
||||||
protected CellChargerStatus _status;
|
|
||||||
|
|
||||||
protected AppearanceComponent _appearanceComponent;
|
|
||||||
|
|
||||||
public abstract double CellChargePercent { get; }
|
|
||||||
|
|
||||||
// Powered items have their own charge rates, this is just a way to have chargers with different rates as well
|
|
||||||
public float TransferRatio => _transferRatio;
|
|
||||||
[ViewVariables]
|
|
||||||
protected float _transferRatio;
|
|
||||||
|
|
||||||
public float TransferEfficiency => _transferEfficiency;
|
|
||||||
[ViewVariables]
|
|
||||||
protected float _transferEfficiency;
|
|
||||||
|
|
||||||
public override void ExposeData(ObjectSerializer serializer)
|
|
||||||
{
|
|
||||||
base.ExposeData(serializer);
|
|
||||||
|
|
||||||
serializer.DataField(ref _transferRatio, "transfer_ratio", 0.1f);
|
|
||||||
serializer.DataField(ref _transferEfficiency, "transfer_efficiency", 0.85f);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
_powerDevice = Owner.GetComponent<PowerDeviceComponent>();
|
|
||||||
if (_powerDevice == null)
|
|
||||||
{
|
|
||||||
var exc = new InvalidOperationException("Chargers requires a PowerDevice to function");
|
|
||||||
Logger.FatalS("charger", exc.Message);
|
|
||||||
throw exc;
|
|
||||||
}
|
|
||||||
_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
|
|
||||||
_powerDevice.OnPowerStateChanged += PowerUpdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This will remove the item directly into the user's hand / floor
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="user"></param>
|
|
||||||
public void RemoveItem(IEntity user)
|
|
||||||
{
|
|
||||||
var heldItem = _container.ContainedEntity;
|
|
||||||
if (heldItem == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_container.Remove(heldItem);
|
|
||||||
if (user.TryGetComponent(out HandsComponent handsComponent))
|
|
||||||
{
|
|
||||||
handsComponent.PutInHandOrDrop(heldItem.GetComponent<ItemComponent>());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (heldItem.TryGetComponent(out ServerBatteryBarrelComponent batteryBarrelComponent))
|
|
||||||
{
|
|
||||||
batteryBarrelComponent.UpdateAppearance();
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void PowerUpdate(object sender, PowerStateEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
UpdateStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract CellChargerStatus GetStatus();
|
|
||||||
protected abstract void TransferPower(float frameTime);
|
|
||||||
|
|
||||||
protected void UpdateStatus()
|
|
||||||
{
|
|
||||||
// Not called UpdateAppearance just because it messes with the load
|
|
||||||
var status = GetStatus();
|
|
||||||
|
|
||||||
if (_status == status)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_status = status;
|
|
||||||
|
|
||||||
switch (_status)
|
|
||||||
{
|
|
||||||
// Update load just in case
|
|
||||||
case CellChargerStatus.Off:
|
|
||||||
_powerDevice.Load = 0;
|
|
||||||
_appearanceComponent?.SetData(CellVisual.Light, CellChargerStatus.Off);
|
|
||||||
break;
|
|
||||||
case CellChargerStatus.Empty:
|
|
||||||
_powerDevice.Load = 0;
|
|
||||||
_appearanceComponent?.SetData(CellVisual.Light, CellChargerStatus.Empty); ;
|
|
||||||
break;
|
|
||||||
case CellChargerStatus.Charging:
|
|
||||||
_appearanceComponent?.SetData(CellVisual.Light, CellChargerStatus.Charging);
|
|
||||||
break;
|
|
||||||
case CellChargerStatus.Charged:
|
|
||||||
_powerDevice.Load = 0;
|
|
||||||
_appearanceComponent?.SetData(CellVisual.Light, CellChargerStatus.Charged);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
_appearanceComponent?.SetData(CellVisual.Occupied, _container.ContainedEntity != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnUpdate(float frameTime)
|
|
||||||
{
|
|
||||||
if (_status == CellChargerStatus.Empty || _status == CellChargerStatus.Charged ||
|
|
||||||
_container.ContainedEntity == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TransferPower(frameTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,193 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
|
||||||
using Content.Server.Utility;
|
|
||||||
using Content.Shared.GameObjects;
|
|
||||||
using Content.Shared.GameObjects.Components.Power;
|
|
||||||
using Content.Shared.GameObjects.EntitySystems;
|
|
||||||
using Content.Shared.Interfaces;
|
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Server.GameObjects.Components.Container;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Power.Chargers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// This is used for the standalone cell rechargers (e.g. from a flashlight)
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
[ComponentReference(typeof(IActivate))]
|
|
||||||
[ComponentReference(typeof(IInteractUsing))]
|
|
||||||
public sealed class PowerCellChargerComponent : BaseCharger, IActivate, IInteractUsing
|
|
||||||
{
|
|
||||||
public override string Name => "PowerCellCharger";
|
|
||||||
public override double CellChargePercent => _container.ContainedEntity != null ?
|
|
||||||
_container.ContainedEntity.GetComponent<PowerCellComponent>().Charge /
|
|
||||||
_container.ContainedEntity.GetComponent<PowerCellComponent>().Capacity * 100 : 0.0f;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
_powerDevice = Owner.GetComponent<PowerDeviceComponent>();
|
|
||||||
_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
|
|
||||||
_powerDevice.OnPowerStateChanged += PowerUpdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
var result = TryInsertItem(eventArgs.Using);
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var localizationManager = IoCManager.Resolve<ILocalizationManager>();
|
|
||||||
eventArgs.User.PopupMessage(Owner, localizationManager.GetString("Unable to insert capacitor"));
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IActivate.Activate(ActivateEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
RemoveItem(eventArgs.User);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Verb]
|
|
||||||
private sealed class InsertVerb : Verb<PowerCellChargerComponent>
|
|
||||||
{
|
|
||||||
protected override void GetData(IEntity user, PowerCellChargerComponent component, VerbData data)
|
|
||||||
{
|
|
||||||
if (!ActionBlockerSystem.CanInteract(user))
|
|
||||||
{
|
|
||||||
data.Visibility = VerbVisibility.Invisible;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!user.TryGetComponent(out HandsComponent handsComponent))
|
|
||||||
{
|
|
||||||
data.Visibility = VerbVisibility.Invisible;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (component._container.ContainedEntity != null || handsComponent.GetActiveHand == null)
|
|
||||||
{
|
|
||||||
data.Visibility = VerbVisibility.Disabled;
|
|
||||||
data.Text = "Insert";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.Text = $"Insert {handsComponent.GetActiveHand.Owner.Name}";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Activate(IEntity user, PowerCellChargerComponent component)
|
|
||||||
{
|
|
||||||
if (!user.TryGetComponent(out HandsComponent handsComponent))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handsComponent.GetActiveHand == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var userItem = handsComponent.GetActiveHand.Owner;
|
|
||||||
handsComponent.Drop(userItem);
|
|
||||||
component.TryInsertItem(userItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Verb]
|
|
||||||
private sealed class EjectVerb : Verb<PowerCellChargerComponent>
|
|
||||||
{
|
|
||||||
protected override void GetData(IEntity user, PowerCellChargerComponent component, VerbData data)
|
|
||||||
{
|
|
||||||
if (!ActionBlockerSystem.CanInteract(user))
|
|
||||||
{
|
|
||||||
data.Visibility = VerbVisibility.Invisible;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (component._container.ContainedEntity == null)
|
|
||||||
{
|
|
||||||
data.Text = "Eject";
|
|
||||||
data.Visibility = VerbVisibility.Disabled;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.Text = $"Eject {component._container.ContainedEntity.Name}";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Activate(IEntity user, PowerCellChargerComponent component)
|
|
||||||
{
|
|
||||||
component.RemoveItem(user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryInsertItem(IEntity entity)
|
|
||||||
{
|
|
||||||
if (!entity.HasComponent<PowerCellComponent>() ||
|
|
||||||
_container.ContainedEntity != null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_container.Insert(entity))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
UpdateStatus();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override CellChargerStatus GetStatus()
|
|
||||||
{
|
|
||||||
if (!_powerDevice.Powered)
|
|
||||||
{
|
|
||||||
return CellChargerStatus.Off;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_container.ContainedEntity == null)
|
|
||||||
{
|
|
||||||
return CellChargerStatus.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_container.ContainedEntity.TryGetComponent(out PowerCellComponent component) &&
|
|
||||||
Math.Abs(component.Capacity - component.Charge) < 0.01)
|
|
||||||
{
|
|
||||||
return CellChargerStatus.Charged;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CellChargerStatus.Charging;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void TransferPower(float frameTime)
|
|
||||||
{
|
|
||||||
// Two numbers: One for how much power actually goes into the device (chargeAmount) and
|
|
||||||
// chargeLoss which is how much is drawn from the powernet
|
|
||||||
var cellComponent = _container.ContainedEntity.GetComponent<PowerCellComponent>();
|
|
||||||
var chargeLoss = cellComponent.RequestCharge(frameTime) * _transferRatio;
|
|
||||||
_powerDevice.Load = chargeLoss;
|
|
||||||
|
|
||||||
if (!_powerDevice.Powered)
|
|
||||||
{
|
|
||||||
// No power: Event should update to Off status
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var chargeAmount = chargeLoss * _transferEfficiency;
|
|
||||||
|
|
||||||
cellComponent.AddCharge(chargeAmount);
|
|
||||||
// Just so the sprite won't be set to 99.99999% visibility
|
|
||||||
if (cellComponent.Capacity - cellComponent.Charge < 0.01)
|
|
||||||
{
|
|
||||||
cellComponent.Charge = cellComponent.Capacity;
|
|
||||||
}
|
|
||||||
UpdateStatus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,183 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels;
|
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
|
||||||
using Content.Shared.GameObjects;
|
|
||||||
using Content.Shared.GameObjects.Components.Power;
|
|
||||||
using Content.Shared.GameObjects.EntitySystems;
|
|
||||||
using Content.Shared.Interfaces;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Power.Chargers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// This is used for the lasergun / flash rechargers
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
[ComponentReference(typeof(IActivate))]
|
|
||||||
[ComponentReference(typeof(IInteractUsing))]
|
|
||||||
public sealed class WeaponCapacitorChargerComponent : BaseCharger, IActivate, IInteractUsing
|
|
||||||
{
|
|
||||||
public override string Name => "WeaponCapacitorCharger";
|
|
||||||
public override double CellChargePercent => _container.ContainedEntity != null ?
|
|
||||||
_container.ContainedEntity.GetComponent<ServerBatteryBarrelComponent>().PowerCell.Charge /
|
|
||||||
_container.ContainedEntity.GetComponent<ServerBatteryBarrelComponent>().PowerCell.Capacity * 100 : 0.0f;
|
|
||||||
|
|
||||||
bool IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
var result = TryInsertItem(eventArgs.Using);
|
|
||||||
if (!result)
|
|
||||||
{
|
|
||||||
var localizationManager = IoCManager.Resolve<ILocalizationManager>();
|
|
||||||
eventArgs.User.PopupMessage(Owner, localizationManager.GetString("Unable to insert capacitor"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IActivate.Activate(ActivateEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
RemoveItem(eventArgs.User);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Verb]
|
|
||||||
private sealed class InsertVerb : Verb<WeaponCapacitorChargerComponent>
|
|
||||||
{
|
|
||||||
protected override void GetData(IEntity user, WeaponCapacitorChargerComponent component, VerbData data)
|
|
||||||
{
|
|
||||||
if (!ActionBlockerSystem.CanInteract(user))
|
|
||||||
{
|
|
||||||
data.Visibility = VerbVisibility.Invisible;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!user.TryGetComponent(out HandsComponent handsComponent))
|
|
||||||
{
|
|
||||||
data.Visibility = VerbVisibility.Invisible;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handsComponent.GetActiveHand == null)
|
|
||||||
{
|
|
||||||
data.Visibility = VerbVisibility.Disabled;
|
|
||||||
data.Text = "Insert";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (component._container.ContainedEntity != null)
|
|
||||||
{
|
|
||||||
data.Visibility = VerbVisibility.Disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.Text = $"Insert {handsComponent.GetActiveHand.Owner.Name}";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Activate(IEntity user, WeaponCapacitorChargerComponent component)
|
|
||||||
{
|
|
||||||
if (!user.TryGetComponent(out HandsComponent handsComponent))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handsComponent.GetActiveHand == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var userItem = handsComponent.GetActiveHand.Owner;
|
|
||||||
handsComponent.Drop(userItem);
|
|
||||||
component.TryInsertItem(userItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Verb]
|
|
||||||
private sealed class EjectVerb : Verb<WeaponCapacitorChargerComponent>
|
|
||||||
{
|
|
||||||
protected override void GetData(IEntity user, WeaponCapacitorChargerComponent component, VerbData data)
|
|
||||||
{
|
|
||||||
if (!ActionBlockerSystem.CanInteract(user))
|
|
||||||
{
|
|
||||||
data.Visibility = VerbVisibility.Invisible;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (component._container.ContainedEntity == null)
|
|
||||||
{
|
|
||||||
data.Visibility = VerbVisibility.Disabled;
|
|
||||||
data.Text = "Eject";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.Text = $"Eject {component._container.ContainedEntity.Name}";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Activate(IEntity user, WeaponCapacitorChargerComponent component)
|
|
||||||
{
|
|
||||||
component.RemoveItem(user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryInsertItem(IEntity entity)
|
|
||||||
{
|
|
||||||
if (!entity.HasComponent<ServerBatteryBarrelComponent>() ||
|
|
||||||
_container.ContainedEntity != null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_container.Insert(entity))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
UpdateStatus();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override CellChargerStatus GetStatus()
|
|
||||||
{
|
|
||||||
if (!_powerDevice.Powered)
|
|
||||||
{
|
|
||||||
return CellChargerStatus.Off;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_container.ContainedEntity == null)
|
|
||||||
{
|
|
||||||
return CellChargerStatus.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_container.ContainedEntity.TryGetComponent(out ServerBatteryBarrelComponent component) &&
|
|
||||||
Math.Abs(component.PowerCell.Capacity - component.PowerCell.Charge) < 0.01)
|
|
||||||
{
|
|
||||||
return CellChargerStatus.Charged;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CellChargerStatus.Charging;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void TransferPower(float frameTime)
|
|
||||||
{
|
|
||||||
// Two numbers: One for how much power actually goes into the device (chargeAmount) and
|
|
||||||
// chargeLoss which is how much is drawn from the powernet
|
|
||||||
var powerCell = _container.ContainedEntity.GetComponent<ServerBatteryBarrelComponent>().PowerCell;
|
|
||||||
var chargeLoss = powerCell.RequestCharge(frameTime) * _transferRatio;
|
|
||||||
_powerDevice.Load = chargeLoss;
|
|
||||||
|
|
||||||
if (!_powerDevice.Powered)
|
|
||||||
{
|
|
||||||
// No power: Event should update to Off status
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var chargeAmount = chargeLoss * _transferEfficiency;
|
|
||||||
|
|
||||||
powerCell.AddCharge(chargeAmount);
|
|
||||||
// Just so the sprite won't be set to 99.99999% visibility
|
|
||||||
if (powerCell.Capacity - powerCell.Charge < 0.01)
|
|
||||||
{
|
|
||||||
powerCell.Charge = powerCell.Capacity;
|
|
||||||
}
|
|
||||||
UpdateStatus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +1,37 @@
|
|||||||
using Content.Shared.GameObjects.Components.Power;
|
using Content.Shared.GameObjects.Components.Power;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Power
|
namespace Content.Server.GameObjects.Components.Power
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Batteries that have update an <see cref="AppearanceComponent"/> based on their charge percent.
|
||||||
|
/// </summary>
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
[ComponentReference(typeof(PowerStorageComponent))]
|
[ComponentReference(typeof(BatteryComponent))]
|
||||||
public class PowerCellComponent : PowerStorageComponent
|
public class PowerCellComponent : BatteryComponent
|
||||||
{
|
{
|
||||||
public override string Name => "PowerCell";
|
public override string Name => "PowerCell";
|
||||||
|
|
||||||
private AppearanceComponent _appearance;
|
private AppearanceComponent _appearance;
|
||||||
|
|
||||||
public override float Charge
|
|
||||||
{
|
|
||||||
get => base.Charge;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
base.Charge = value;
|
|
||||||
_updateAppearance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
_appearance = Owner.GetComponent<AppearanceComponent>();
|
||||||
Owner.TryGetComponent(out _appearance);
|
CurrentCharge = MaxCharge;
|
||||||
|
UpdateVisuals();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DeductCharge(float toDeduct)
|
protected override void OnChargeChanged()
|
||||||
{
|
{
|
||||||
base.DeductCharge(toDeduct);
|
base.OnChargeChanged();
|
||||||
|
UpdateVisuals();
|
||||||
_updateAppearance();
|
|
||||||
ChargeChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AddCharge(float charge)
|
private void UpdateVisuals()
|
||||||
{
|
{
|
||||||
base.AddCharge(charge);
|
_appearance?.SetData(PowerCellVisuals.ChargeLevel, CurrentCharge / MaxCharge);
|
||||||
|
|
||||||
_updateAppearance();
|
|
||||||
ChargeChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void _updateAppearance()
|
|
||||||
{
|
|
||||||
_appearance?.SetData(PowerCellVisuals.ChargeLevel, Charge / Capacity);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,108 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Text;
|
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
|
||||||
using Content.Shared.GameObjects.Components.Power;
|
|
||||||
using Robust.Server.Interfaces.GameObjects;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
|
||||||
using Robust.Shared.Interfaces.GameObjects.Components;
|
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Power
|
|
||||||
{
|
|
||||||
[RegisterComponent]
|
|
||||||
public class PowerDebugTool : SharedPowerDebugTool, IAfterInteract
|
|
||||||
{
|
|
||||||
void IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
if (eventArgs.Target == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var builder = new StringBuilder();
|
|
||||||
|
|
||||||
builder.AppendFormat("Entity: {0} ({1})\n", eventArgs.Target.Name, eventArgs.Target.Uid);
|
|
||||||
|
|
||||||
if (eventArgs.Target.TryGetComponent<PowerNodeComponent>(out var node))
|
|
||||||
{
|
|
||||||
builder.AppendFormat("Power Node:\n");
|
|
||||||
if (node.Parent == null)
|
|
||||||
{
|
|
||||||
builder.Append(" No Powernet!\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var net = node.Parent;
|
|
||||||
builder.AppendFormat(@" Powernet: {0}
|
|
||||||
Wires: {1}, Nodes: {2}
|
|
||||||
Generators: {3}, Loaders: {4},
|
|
||||||
StorageS: {5}, StorageC: {6},
|
|
||||||
Load: {7}, Supply: {8},
|
|
||||||
LAvail: {9}, LDraw: {10},
|
|
||||||
LDemand: {11}, LDemandWS: {12},
|
|
||||||
",
|
|
||||||
net.Uid,
|
|
||||||
net.NodeList.Count, net.WireList.Count,
|
|
||||||
net.GeneratorCount, net.DeviceCount,
|
|
||||||
net.PowerStorageSupplierCount, net.PowerStorageConsumerCount,
|
|
||||||
net.Load, net.Supply,
|
|
||||||
net.LastTotalAvailable, net.LastTotalDraw,
|
|
||||||
net.LastTotalDemand, net.LastTotalDemandWithSuppliers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventArgs.Target.TryGetComponent<PowerDeviceComponent>(out var device))
|
|
||||||
{
|
|
||||||
builder.AppendFormat(@"Power Device:
|
|
||||||
Load: {0} W
|
|
||||||
Priority: {1}
|
|
||||||
Drawtype: {2}, Connected: {3}
|
|
||||||
Powered: {4}
|
|
||||||
", device.Load, device.Priority, device.DrawType, device.Connected, device.Powered);
|
|
||||||
|
|
||||||
if (device.Connected == DrawTypes.Provider || device.Connected == DrawTypes.Both)
|
|
||||||
{
|
|
||||||
builder.Append(" Providers:\n");
|
|
||||||
foreach (var provider in device.AvailableProviders)
|
|
||||||
{
|
|
||||||
var providerTransform = provider.Owner.GetComponent<ITransformComponent>();
|
|
||||||
builder.AppendFormat(" {0} ({1}) @ {2}", provider.Owner.Name, provider.Owner.Uid, providerTransform.GridPosition);
|
|
||||||
if (device.Provider == provider)
|
|
||||||
{
|
|
||||||
builder.Append(" (CURRENT)");
|
|
||||||
}
|
|
||||||
builder.Append('\n');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventArgs.Target.TryGetComponent<PowerStorageNetComponent>(out var storage))
|
|
||||||
{
|
|
||||||
var stateSeconds = (DateTime.Now - storage.LastChargeStateChange).TotalSeconds;
|
|
||||||
builder.AppendFormat(@"Power Storage:
|
|
||||||
Capacity: {0}, Charge: {1}, ChargeRate: {2}, DistributionRate: {3}, ChargePowernet: {4}
|
|
||||||
LastChargeState: {5} ({6}), LastChargeStateChange: {7:0.00} seconds ago.
|
|
||||||
", storage.Capacity, storage.Charge, storage.ChargeRate, storage.DistributionRate, storage.ChargePowernet, storage.LastChargeState, storage.GetChargeState(), stateSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (eventArgs.Target.TryGetComponent<PowerTransferComponent>(out var transfer))
|
|
||||||
{
|
|
||||||
builder.AppendFormat(@"Power Transfer:
|
|
||||||
Powernet: {0}
|
|
||||||
", transfer.Parent.Uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenDataWindowClientSide(eventArgs.User, builder.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OpenDataWindowClientSide(IEntity user, string data)
|
|
||||||
{
|
|
||||||
if (!user.TryGetComponent<IActorComponent>(out var actor))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
SendNetworkMessage(new OpenDataWindowMsg(data), actor.playerSession.ConnectedClient);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,432 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
|
||||||
using Content.Shared.GameObjects.Components.Power;
|
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
|
||||||
using Robust.Shared.Interfaces.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
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Component that requires power to function
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public class PowerDeviceComponent : Component, IExamine
|
|
||||||
{
|
|
||||||
public override string Name => "PowerDevice";
|
|
||||||
|
|
||||||
protected override void Startup()
|
|
||||||
{
|
|
||||||
base.Startup();
|
|
||||||
if (DrawType != DrawTypes.Node)
|
|
||||||
{
|
|
||||||
var componentMgr = IoCManager.Resolve<IComponentManager>();
|
|
||||||
AvailableProviders = componentMgr.GetAllComponents<PowerProviderComponent>().Where(x => x.CanServiceDevice(this)).ToList();
|
|
||||||
ConnectToBestProvider();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual bool SaveLoad => true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The method of draw we will try to use to place our load set via component parameter, defaults to using power providers
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public DrawTypes DrawType
|
|
||||||
{
|
|
||||||
get => _drawType ?? DefaultDrawType;
|
|
||||||
protected set => _drawType = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DrawTypes? _drawType;
|
|
||||||
|
|
||||||
protected virtual DrawTypes DefaultDrawType => DrawTypes.Provider;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The power draw method we are currently connected to and using
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public DrawTypes Connected { get; protected set; } = DrawTypes.None;
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
public bool Powered { get; private set; } = false;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Is an external power source currently available?
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public bool ExternalPowered
|
|
||||||
{
|
|
||||||
get => _externalPowered;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_externalPowered = value;
|
|
||||||
UpdatePowered();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private bool _externalPowered = false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Is an internal power source currently available?
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
protected bool InternalPowered
|
|
||||||
{
|
|
||||||
get => _internalPowered;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_internalPowered = value;
|
|
||||||
UpdatePowered();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private bool _internalPowered = false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Priority for powernet draw, lower will draw first, defined in powernet.cs
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public virtual Powernet.Priority Priority
|
|
||||||
{
|
|
||||||
get => _priority;
|
|
||||||
protected set => _priority = value;
|
|
||||||
}
|
|
||||||
private Powernet.Priority _priority = Powernet.Priority.Medium;
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public bool IsPowerCut
|
|
||||||
{
|
|
||||||
get => _isPowerCut;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_isPowerCut = value;
|
|
||||||
UpdatePowered();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private float _load = 100; //arbitrary magic number to start
|
|
||||||
/// <summary>
|
|
||||||
/// Power load from this entity.
|
|
||||||
/// In Watts.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public float Load
|
|
||||||
{
|
|
||||||
get => _load;
|
|
||||||
set => UpdateLoad(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// All the power providers that we are within range of
|
|
||||||
/// </summary>
|
|
||||||
public List<PowerProviderComponent> AvailableProviders = new List<PowerProviderComponent>();
|
|
||||||
|
|
||||||
|
|
||||||
private PowerProviderComponent _provider;
|
|
||||||
private bool _isPowerCut;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A power provider that will handle our load, if we are linked to any
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public PowerProviderComponent Provider
|
|
||||||
{
|
|
||||||
get => _provider;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
Connected = DrawTypes.Provider;
|
|
||||||
if (_provider != null)
|
|
||||||
{
|
|
||||||
_provider.RemoveDevice(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
_provider = value;
|
|
||||||
if (value != null)
|
|
||||||
{
|
|
||||||
_provider.AddDevice(this);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Connected = DrawTypes.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public event EventHandler<PowerStateEventArgs> OnPowerStateChanged;
|
|
||||||
|
|
||||||
public override void OnAdd()
|
|
||||||
{
|
|
||||||
base.OnAdd();
|
|
||||||
|
|
||||||
if (DrawType == DrawTypes.Node || DrawType == DrawTypes.Both)
|
|
||||||
{
|
|
||||||
if (!Owner.TryGetComponent(out PowerNodeComponent node))
|
|
||||||
{
|
|
||||||
Owner.AddComponent<PowerNodeComponent>();
|
|
||||||
node = Owner.GetComponent<PowerNodeComponent>();
|
|
||||||
}
|
|
||||||
node.OnPowernetConnect += PowernetConnect;
|
|
||||||
node.OnPowernetDisconnect += PowernetDisconnect;
|
|
||||||
node.OnPowernetRegenerate += PowernetRegenerate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Shutdown()
|
|
||||||
{
|
|
||||||
if (Owner.TryGetComponent(out PowerNodeComponent node))
|
|
||||||
{
|
|
||||||
if (node.Parent != null && node.Parent.HasDevice(this))
|
|
||||||
{
|
|
||||||
node.Parent.RemoveDevice(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
node.OnPowernetConnect -= PowernetConnect;
|
|
||||||
node.OnPowernetDisconnect -= PowernetDisconnect;
|
|
||||||
node.OnPowernetRegenerate -= PowernetRegenerate;
|
|
||||||
}
|
|
||||||
|
|
||||||
Connected = DrawTypes.None;
|
|
||||||
|
|
||||||
if (Provider != null)
|
|
||||||
{
|
|
||||||
Provider = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ExposeData(ObjectSerializer serializer)
|
|
||||||
{
|
|
||||||
base.ExposeData(serializer);
|
|
||||||
|
|
||||||
var drawType = DrawType;
|
|
||||||
serializer.DataField(ref drawType, "drawtype", DefaultDrawType);
|
|
||||||
DrawType = drawType;
|
|
||||||
serializer.DataField(ref _priority, "priority", Powernet.Priority.Medium);
|
|
||||||
|
|
||||||
if (SaveLoad)
|
|
||||||
{
|
|
||||||
serializer.DataField(ref _load, "load", 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IExamine.Examine(FormattedMessage message, bool inDetailsRange)
|
|
||||||
{
|
|
||||||
var loc = IoCManager.Resolve<ILocalizationManager>();
|
|
||||||
|
|
||||||
if (!Powered && inDetailsRange)
|
|
||||||
{
|
|
||||||
message.AddMarkup(loc.GetString("The device is [color=orange]not powered[/color]."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateLoad(float value)
|
|
||||||
{
|
|
||||||
var oldLoad = _load;
|
|
||||||
_load = value;
|
|
||||||
if (Connected == DrawTypes.Node)
|
|
||||||
{
|
|
||||||
var node = Owner.GetComponent<PowerNodeComponent>();
|
|
||||||
node.Parent.UpdateDevice(this, oldLoad);
|
|
||||||
}
|
|
||||||
else if (Connected == DrawTypes.Provider)
|
|
||||||
{
|
|
||||||
Provider.UpdateDevice(this, oldLoad);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the state of whether or not this device is powered,
|
|
||||||
/// and fires off events if said state has changed.
|
|
||||||
/// </summary>
|
|
||||||
private void UpdatePowered()
|
|
||||||
{
|
|
||||||
var oldPowered = Powered;
|
|
||||||
Powered = !IsPowerCut && (ExternalPowered || InternalPowered);
|
|
||||||
|
|
||||||
if (oldPowered != Powered)
|
|
||||||
{
|
|
||||||
OnPowerStateChanged?.Invoke(this, new PowerStateEventArgs(Powered));
|
|
||||||
|
|
||||||
if (Owner.TryGetComponent(out AppearanceComponent appearance))
|
|
||||||
{
|
|
||||||
appearance.SetData(PowerDeviceVisuals.Powered, Powered);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Register a new power provider as a possible connection to this device
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="provider"></param>
|
|
||||||
public void AddProvider(PowerProviderComponent provider)
|
|
||||||
{
|
|
||||||
AvailableProviders.Add(provider);
|
|
||||||
|
|
||||||
if (Connected != DrawTypes.Node)
|
|
||||||
{
|
|
||||||
ConnectToBestProvider();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Find the nearest registered power provider and connect to it
|
|
||||||
/// </summary>
|
|
||||||
private void ConnectToBestProvider()
|
|
||||||
{
|
|
||||||
//Any values we can connect to or are we already connected to a node, cancel!
|
|
||||||
if (!AvailableProviders.Any() || Connected == DrawTypes.Node || Deleted || Owner.Deleted)
|
|
||||||
return;
|
|
||||||
|
|
||||||
//Get the starting value for our loop
|
|
||||||
var position = Owner.GetComponent<ITransformComponent>().WorldPosition;
|
|
||||||
var bestprovider = AvailableProviders[0];
|
|
||||||
|
|
||||||
//If we are already connected to a power provider we need to do a loop to find the nearest one, otherwise skip it and use first entry
|
|
||||||
if (Connected == DrawTypes.Provider)
|
|
||||||
{
|
|
||||||
var bestdistance = (bestprovider.Owner.GetComponent<ITransformComponent>().WorldPosition - position).LengthSquared;
|
|
||||||
|
|
||||||
foreach (var availprovider in AvailableProviders)
|
|
||||||
{
|
|
||||||
if (availprovider.Owner.Deleted)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
//Find distance to new provider
|
|
||||||
var distance = (availprovider.Owner.GetComponent<ITransformComponent>().WorldPosition - position).LengthSquared;
|
|
||||||
|
|
||||||
//If new provider distance is shorter it becomes new best possible provider
|
|
||||||
if (distance < bestdistance)
|
|
||||||
{
|
|
||||||
bestdistance = distance;
|
|
||||||
bestprovider = availprovider;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Provider != bestprovider)
|
|
||||||
Provider = bestprovider;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove a power provider from being a possible connection to this device
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="provider"></param>
|
|
||||||
public void RemoveProvider(PowerProviderComponent provider)
|
|
||||||
{
|
|
||||||
if (!AvailableProviders.Contains(provider))
|
|
||||||
return;
|
|
||||||
|
|
||||||
AvailableProviders.Remove(provider);
|
|
||||||
|
|
||||||
if (provider == Provider)
|
|
||||||
{
|
|
||||||
Provider = null;
|
|
||||||
ExternalPowered = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Connected != DrawTypes.Node)
|
|
||||||
{
|
|
||||||
ConnectToBestProvider();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Node has become anchored to a powernet
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender"></param>
|
|
||||||
/// <param name="eventarg"></param>
|
|
||||||
protected virtual void PowernetConnect(object sender, PowernetEventArgs eventarg)
|
|
||||||
{
|
|
||||||
//This sets connected = none so it must be first
|
|
||||||
Provider = null;
|
|
||||||
|
|
||||||
eventarg.Powernet.AddDevice(this);
|
|
||||||
Connected = DrawTypes.Node;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Powernet wire was remove so we need to regenerate the powernet
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender"></param>
|
|
||||||
/// <param name="eventarg"></param>
|
|
||||||
protected virtual void PowernetRegenerate(object sender, PowernetEventArgs eventarg)
|
|
||||||
{
|
|
||||||
eventarg.Powernet.AddDevice(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Node has become unanchored from a powernet
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender"></param>
|
|
||||||
/// <param name="eventarg"></param>
|
|
||||||
protected virtual void PowernetDisconnect(object sender, PowernetEventArgs eventarg)
|
|
||||||
{
|
|
||||||
eventarg.Powernet.RemoveDevice(this);
|
|
||||||
Connected = DrawTypes.None;
|
|
||||||
|
|
||||||
ConnectToBestProvider();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Process mechanism to keep track of internal battery and power status.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="frametime">Time since the last process frame.</param>
|
|
||||||
internal virtual void ProcessInternalPower(float frametime)
|
|
||||||
{
|
|
||||||
if (Owner.TryGetComponent<PowerStorageComponent>(out var storage) && storage.CanDeductCharge(Load))
|
|
||||||
{
|
|
||||||
// We still keep InternalPowered correct if connected externally,
|
|
||||||
// but don't use it.
|
|
||||||
if (!ExternalPowered)
|
|
||||||
{
|
|
||||||
storage.DeductCharge(Load);
|
|
||||||
}
|
|
||||||
InternalPowered = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
InternalPowered = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The different methods that a <see cref="PowerDeviceComponent"/> can use to connect to a power network.
|
|
||||||
/// </summary>
|
|
||||||
public enum DrawTypes
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// This device cannot be connected to a power network.
|
|
||||||
/// </summary>
|
|
||||||
None = 0,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This device can connect to a <see cref=""/>
|
|
||||||
/// </summary>
|
|
||||||
Node = 1,
|
|
||||||
Provider = 2,
|
|
||||||
Both = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PowerStateEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
public readonly bool Powered;
|
|
||||||
|
|
||||||
public PowerStateEventArgs(bool powered)
|
|
||||||
{
|
|
||||||
Powered = powered;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Serialization;
|
|
||||||
using Robust.Shared.ViewVariables;
|
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Power
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Component that creates power and supplies it to the powernet
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public class PowerGeneratorComponent : Component
|
|
||||||
{
|
|
||||||
public override string Name => "PowerGenerator";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Power supply from this entity
|
|
||||||
/// </summary>
|
|
||||||
private float _supply = 1000; //arbitrary initial magic number to start
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public float Supply
|
|
||||||
{
|
|
||||||
get => _supply;
|
|
||||||
set { UpdateSupply(value); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ExposeData(ObjectSerializer serializer)
|
|
||||||
{
|
|
||||||
base.ExposeData(serializer);
|
|
||||||
|
|
||||||
serializer.DataField(ref _supply, "supply", 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnAdd()
|
|
||||||
{
|
|
||||||
base.OnAdd();
|
|
||||||
|
|
||||||
if (!Owner.TryGetComponent(out PowerNodeComponent node))
|
|
||||||
{
|
|
||||||
Owner.AddComponent<PowerNodeComponent>();
|
|
||||||
node = Owner.GetComponent<PowerNodeComponent>();
|
|
||||||
}
|
|
||||||
node.OnPowernetConnect += PowernetConnect;
|
|
||||||
node.OnPowernetDisconnect += PowernetDisconnect;
|
|
||||||
node.OnPowernetRegenerate += PowernetRegenerate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnRemove()
|
|
||||||
{
|
|
||||||
if (Owner.TryGetComponent(out PowerNodeComponent node))
|
|
||||||
{
|
|
||||||
if (node.Parent != null)
|
|
||||||
{
|
|
||||||
node.Parent.RemoveGenerator(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
node.OnPowernetConnect -= PowernetConnect;
|
|
||||||
node.OnPowernetDisconnect -= PowernetDisconnect;
|
|
||||||
node.OnPowernetRegenerate -= PowernetRegenerate;
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnRemove();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateSupply(float value)
|
|
||||||
{
|
|
||||||
_supply = value;
|
|
||||||
var node = Owner.GetComponent<PowerNodeComponent>();
|
|
||||||
node?.Parent?.UpdateGenerator(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Node has become anchored to a powernet
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender"></param>
|
|
||||||
/// <param name="eventarg"></param>
|
|
||||||
private void PowernetConnect(object sender, PowernetEventArgs eventarg)
|
|
||||||
{
|
|
||||||
eventarg.Powernet.AddGenerator(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Node has had its powernet regenerated
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender"></param>
|
|
||||||
/// <param name="eventarg"></param>
|
|
||||||
private void PowernetRegenerate(object sender, PowernetEventArgs eventarg)
|
|
||||||
{
|
|
||||||
eventarg.Powernet.AddGenerator(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Node has become unanchored from a powernet
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender"></param>
|
|
||||||
/// <param name="eventarg"></param>
|
|
||||||
private void PowernetDisconnect(object sender, PowernetEventArgs eventarg)
|
|
||||||
{
|
|
||||||
eventarg.Powernet.RemoveGenerator(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Power.PowerNetComponents
|
||||||
|
{
|
||||||
|
public abstract class BasePowerNetComponent : BaseNetConnectorComponent<IPowerNet>
|
||||||
|
{
|
||||||
|
protected override IPowerNet NullNet => PowerNetNodeGroup.NullNet;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Power.PowerNetComponents
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Uses charge from a <see cref="BatteryComponent"/> to supply power via a <see cref="PowerSupplierComponent"/>.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public class BatteryDischargerComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name => "BatteryDischarger";
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private BatteryComponent _battery;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private PowerSupplierComponent _supplier;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public int ActiveSupplyRate { get => _activeSupplyRate; set => SetActiveSupplyRate(value); }
|
||||||
|
private int _activeSupplyRate;
|
||||||
|
|
||||||
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
|
{
|
||||||
|
base.ExposeData(serializer);
|
||||||
|
serializer.DataField(ref _activeSupplyRate, "activeSupplyRate", 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
_battery = Owner.GetComponent<BatteryComponent>();
|
||||||
|
_supplier = Owner.GetComponent<PowerSupplierComponent>();
|
||||||
|
UpdateSupplyRate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(float frameTime)
|
||||||
|
{
|
||||||
|
//Simplified implementation - if the battery is empty, and charge is being added to the battery
|
||||||
|
//at a lower rate that this is using it, the charge is used without creating power supply.
|
||||||
|
_battery.CurrentCharge -= ActiveSupplyRate * frameTime;
|
||||||
|
UpdateSupplyRate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateSupplyRate()
|
||||||
|
{
|
||||||
|
if (_battery.BatteryState == BatteryState.Empty)
|
||||||
|
{
|
||||||
|
SetSupplierSupplyRate(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetSupplierSupplyRate(ActiveSupplyRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetSupplierSupplyRate(int newSupplierSupplyRate)
|
||||||
|
{
|
||||||
|
if (_supplier.SupplyRate != newSupplierSupplyRate)
|
||||||
|
{
|
||||||
|
_supplier.SupplyRate = newSupplierSupplyRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetActiveSupplyRate(int newEnabledSupplyRate)
|
||||||
|
{
|
||||||
|
_activeSupplyRate = newEnabledSupplyRate;
|
||||||
|
UpdateSupplyRate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Power.PowerNetComponents
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Takes power via a <see cref="PowerConsumerComponent"/> to charge a <see cref="BatteryComponent"/>.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public class BatteryStorageComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name => "BatteryStorage";
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public int ActiveDrawRate { get => _activeDrawRate; set => SetActiveDrawRate(value); }
|
||||||
|
private int _activeDrawRate;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private BatteryComponent _battery;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
public PowerConsumerComponent Consumer { get; private set; }
|
||||||
|
|
||||||
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
|
{
|
||||||
|
base.ExposeData(serializer);
|
||||||
|
serializer.DataField(ref _activeDrawRate, "activeDrawRate", 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
_battery = Owner.GetComponent<BatteryComponent>();
|
||||||
|
Consumer = Owner.GetComponent<PowerConsumerComponent>();
|
||||||
|
UpdateDrawRate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update(float frameTime)
|
||||||
|
{
|
||||||
|
//Simplified implementation - If a frame adds more power to a partially full battery than it can hold, the power is lost.
|
||||||
|
_battery.CurrentCharge += Consumer.ReceivedPower * frameTime;
|
||||||
|
UpdateDrawRate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateDrawRate()
|
||||||
|
{
|
||||||
|
if (_battery.BatteryState == BatteryState.Full)
|
||||||
|
{
|
||||||
|
SetConsumerDraw(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetConsumerDraw(ActiveDrawRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetConsumerDraw(int newConsumerDrawRate)
|
||||||
|
{
|
||||||
|
if (Consumer.DrawRate != newConsumerDrawRate)
|
||||||
|
{
|
||||||
|
Consumer.DrawRate = newConsumerDrawRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetActiveDrawRate(int newEnabledDrawRate)
|
||||||
|
{
|
||||||
|
_activeDrawRate = newEnabledDrawRate;
|
||||||
|
UpdateDrawRate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Power.PowerNetComponents
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
public class PowerConsumerComponent : BasePowerNetComponent
|
||||||
|
{
|
||||||
|
public override string Name => "PowerConsumer";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How much power this needs to be fully powered.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public int DrawRate { get => _drawRate; set => SetDrawRate(value); }
|
||||||
|
private int _drawRate;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines which <see cref="PowerConsumerComponent"/>s receive power when there is not enough
|
||||||
|
/// power for each.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public Priority Priority { get => _priority; set => SetPriority(value); }
|
||||||
|
private Priority _priority;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How much power this is currently receiving from <see cref="PowerSupplierComponent"/>s.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public int ReceivedPower { get => _receivedPower; set => SetReceivedPower(value); }
|
||||||
|
private int _receivedPower;
|
||||||
|
|
||||||
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
|
{
|
||||||
|
base.ExposeData(serializer);
|
||||||
|
serializer.DataField(ref _drawRate, "drawRate", 0);
|
||||||
|
serializer.DataField(ref _priority, "priority", Priority.First);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void AddSelfToNet(IPowerNet powerNet)
|
||||||
|
{
|
||||||
|
powerNet.AddConsumer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void RemoveSelfFromNet(IPowerNet powerNet)
|
||||||
|
{
|
||||||
|
powerNet.RemoveConsumer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetDrawRate(int newDrawRate)
|
||||||
|
{
|
||||||
|
var oldDrawRate = DrawRate;
|
||||||
|
_drawRate = newDrawRate; //must be set before updating powernet, as it checks the DrawRate of every consumer
|
||||||
|
Net.UpdateConsumerDraw(this, oldDrawRate, newDrawRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetReceivedPower(int newReceivedPower)
|
||||||
|
{
|
||||||
|
Debug.Assert(newReceivedPower >= 0 && newReceivedPower <= DrawRate);
|
||||||
|
_receivedPower = newReceivedPower;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetPriority(Priority newPriority)
|
||||||
|
{
|
||||||
|
Net.UpdateConsumerPriority(this, Priority, newPriority);
|
||||||
|
_priority = newPriority;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Priority
|
||||||
|
{
|
||||||
|
First,
|
||||||
|
Last,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Power.PowerNetComponents
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
public class PowerSupplierComponent : BasePowerNetComponent
|
||||||
|
{
|
||||||
|
public override string Name => "PowerSupplier";
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public int SupplyRate { get => _supplyRate; set => SetSupplyRate(value); }
|
||||||
|
private int _supplyRate;
|
||||||
|
|
||||||
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
|
{
|
||||||
|
base.ExposeData(serializer);
|
||||||
|
serializer.DataField(ref _supplyRate, "supplyRate", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void AddSelfToNet(IPowerNet powerNet)
|
||||||
|
{
|
||||||
|
powerNet.AddSupplier(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void RemoveSelfFromNet(IPowerNet powerNet)
|
||||||
|
{
|
||||||
|
powerNet.RemoveSupplier(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetSupplyRate(int newSupplyRate)
|
||||||
|
{
|
||||||
|
Net.UpdateSupplierSupply(this, SupplyRate, newSupplyRate);
|
||||||
|
_supplyRate = newSupplyRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
using Content.Server.GameObjects.Components.Power.PowerNetComponents;
|
||||||
|
using Content.Shared.GameObjects.Components.Power;
|
||||||
|
using Content.Shared.Utility;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Interfaces.Timing;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Power
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Handles the "user-facing" side of the actual SMES object.
|
||||||
|
/// This is operations that are specific to the SMES, like UI and visuals.
|
||||||
|
/// Code interfacing with the powernet is handled in <see cref="BatteryStorageComponent"/> and <see cref="BatteryDischargerComponent"/>.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public class SmesComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name => "Smes";
|
||||||
|
|
||||||
|
private BatteryComponent _battery;
|
||||||
|
|
||||||
|
private AppearanceComponent _appearance;
|
||||||
|
|
||||||
|
private int _lastChargeLevel = 0;
|
||||||
|
|
||||||
|
private TimeSpan _lastChargeLevelChange;
|
||||||
|
|
||||||
|
private ChargeState _lastChargeState;
|
||||||
|
|
||||||
|
private TimeSpan _lastChargeStateChange;
|
||||||
|
|
||||||
|
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>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnUpdate()
|
||||||
|
{
|
||||||
|
var newLevel = GetNewChargeLevel();
|
||||||
|
if (newLevel != _lastChargeLevel && _lastChargeLevelChange + TimeSpan.FromSeconds(VisualsChangeDelay) < _gameTiming.CurTime)
|
||||||
|
{
|
||||||
|
_lastChargeLevel = newLevel;
|
||||||
|
_lastChargeLevelChange = _gameTiming.CurTime;
|
||||||
|
_appearance.SetData(SmesVisuals.LastChargeLevel, newLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
var newChargeState = GetNewChargeState();
|
||||||
|
if (newChargeState != _lastChargeState && _lastChargeStateChange + TimeSpan.FromSeconds(VisualsChangeDelay) < _gameTiming.CurTime)
|
||||||
|
{
|
||||||
|
_lastChargeState = newChargeState;
|
||||||
|
_lastChargeStateChange = _gameTiming.CurTime;
|
||||||
|
_appearance.SetData(SmesVisuals.LastChargeState, newChargeState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetNewChargeLevel()
|
||||||
|
{
|
||||||
|
return ContentHelpers.RoundToLevels(_battery.CurrentCharge, _battery.MaxCharge, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ChargeState GetNewChargeState()
|
||||||
|
{
|
||||||
|
var supplier = Owner.GetComponent<PowerSupplierComponent>();
|
||||||
|
var consumer = Owner.GetComponent<PowerConsumerComponent>();
|
||||||
|
if (supplier.SupplyRate > 0 && consumer.DrawRate != consumer.ReceivedPower)
|
||||||
|
{
|
||||||
|
return ChargeState.Discharging;
|
||||||
|
}
|
||||||
|
else if (supplier.SupplyRate == 0 && consumer.DrawRate > 0)
|
||||||
|
{
|
||||||
|
return ChargeState.Charging;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return ChargeState.Still;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
using Content.Server.GameObjects.Components.Power;
|
using Content.Server.GameObjects.Components.Power;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
using Content.Server.Interfaces.GameTicking;
|
using Content.Server.Interfaces.GameTicking;
|
||||||
@@ -20,9 +21,9 @@ namespace Content.Server.GameObjects.Components.Power
|
|||||||
#pragma warning restore 649
|
#pragma warning restore 649
|
||||||
|
|
||||||
private BoundUserInterface _userInterface;
|
private BoundUserInterface _userInterface;
|
||||||
private PowerDeviceComponent _powerDevice;
|
private PowerReceiverComponent _powerReceiver;
|
||||||
private PowerSolarSystem _powerSolarSystem;
|
private PowerSolarSystem _powerSolarSystem;
|
||||||
private bool Powered => _powerDevice.Powered;
|
private bool Powered => _powerReceiver.Powered;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -30,7 +31,7 @@ namespace Content.Server.GameObjects.Components.Power
|
|||||||
|
|
||||||
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(SolarControlConsoleUiKey.Key);
|
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(SolarControlConsoleUiKey.Key);
|
||||||
_userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
|
_userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
|
||||||
_powerDevice = Owner.GetComponent<PowerDeviceComponent>();
|
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
|
||||||
_powerSolarSystem = _entitySystemManager.GetEntitySystem<PowerSolarSystem>();
|
_powerSolarSystem = _entitySystemManager.GetEntitySystem<PowerSolarSystem>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using Content.Server.GameObjects.Components.Damage;
|
using Content.Server.GameObjects.Components.Damage;
|
||||||
|
using Content.Server.GameObjects.Components.Power.PowerNetComponents;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
using Content.Shared.Audio;
|
using Content.Shared.Audio;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
@@ -27,14 +28,14 @@ namespace Content.Server.GameObjects.Components.Power
|
|||||||
{
|
{
|
||||||
public override string Name => "SolarPanel";
|
public override string Name => "SolarPanel";
|
||||||
|
|
||||||
private PowerGeneratorComponent _powerGenerator;
|
private PowerSupplierComponent _powerSupplier;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maximum supply output by this panel (coverage = 1)
|
/// Maximum supply output by this panel (coverage = 1)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private float _maxSupply = 1500;
|
private int _maxSupply = 1500;
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public float MaxSupply
|
public int MaxSupply
|
||||||
{
|
{
|
||||||
get => _maxSupply;
|
get => _maxSupply;
|
||||||
set {
|
set {
|
||||||
@@ -72,15 +73,15 @@ namespace Content.Server.GameObjects.Components.Power
|
|||||||
|
|
||||||
private void UpdateSupply()
|
private void UpdateSupply()
|
||||||
{
|
{
|
||||||
if (_powerGenerator != null)
|
if (_powerSupplier != null)
|
||||||
_powerGenerator.Supply = _maxSupply * _coverage;
|
_powerSupplier.SupplyRate = (int) (_maxSupply * _coverage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
_powerGenerator = Owner.GetComponent<PowerGeneratorComponent>();
|
_powerSupplier = Owner.GetComponent<PowerSupplierComponent>();
|
||||||
UpdateSupply();
|
UpdateSupply();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using Robust.Server.Interfaces.GameObjects;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.GameObjects.Components.Transform;
|
|
||||||
using Robust.Shared.Interfaces.GameObjects.Components;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.ViewVariables;
|
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Power
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Component that connects to the powernet
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public class PowerNodeComponent : Component
|
|
||||||
{
|
|
||||||
public override string Name => "PowerNode";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The powernet this node is connected to
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public Powernet Parent { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An event handling when this node connects to a powernet
|
|
||||||
/// </summary>
|
|
||||||
public event EventHandler<PowernetEventArgs> OnPowernetConnect;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An event handling when this node disconnects from a powernet
|
|
||||||
/// </summary>
|
|
||||||
public event EventHandler<PowernetEventArgs> OnPowernetDisconnect;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An event that registers us to a regenerating powernet
|
|
||||||
/// </summary>
|
|
||||||
public event EventHandler<PowernetEventArgs> OnPowernetRegenerate;
|
|
||||||
|
|
||||||
protected override void Startup()
|
|
||||||
{
|
|
||||||
base.Startup();
|
|
||||||
|
|
||||||
TryCreatePowernetConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnRemove()
|
|
||||||
{
|
|
||||||
DisconnectFromPowernet();
|
|
||||||
|
|
||||||
base.OnRemove();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Find a nearby wire which will have a powernet and connect ourselves to its powernet
|
|
||||||
/// </summary>
|
|
||||||
public void TryCreatePowernetConnection()
|
|
||||||
{
|
|
||||||
if (Parent != null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var position = Owner.Transform.WorldPosition;
|
|
||||||
|
|
||||||
var sgc = Owner.GetComponent<SnapGridComponent>();
|
|
||||||
var wire = sgc.GetCardinalNeighborCells()
|
|
||||||
.SelectMany(x => x.GetLocal()).Distinct()
|
|
||||||
.Select(x => x.TryGetComponent<PowerTransferComponent>(out var c) ? c : null)
|
|
||||||
.Where(x => x != null).Distinct()
|
|
||||||
.ToArray()
|
|
||||||
.OrderByDescending(x => (x.Owner.Transform.WorldPosition - position).Length)
|
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
if (wire?.Parent != null)
|
|
||||||
{
|
|
||||||
ConnectToPowernet(wire.Parent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Triggers event telling power components that we connected to a powernet
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="toconnect"></param>
|
|
||||||
public void ConnectToPowernet(Powernet toconnect)
|
|
||||||
{
|
|
||||||
Parent = toconnect;
|
|
||||||
Parent.NodeList.Add(this);
|
|
||||||
OnPowernetConnect?.Invoke(this, new PowernetEventArgs(Parent));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Triggers event telling power components that we haven't disconnected but have readded ourselves to a regenerated powernet
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="toconnect"></param>
|
|
||||||
public void RegeneratePowernet(Powernet toconnect)
|
|
||||||
{
|
|
||||||
//This removes the device from things that will be powernet disconnected when dirty powernet is killed
|
|
||||||
Parent.NodeList.Remove(this);
|
|
||||||
|
|
||||||
Parent = toconnect;
|
|
||||||
Parent.NodeList.Add(this);
|
|
||||||
OnPowernetRegenerate?.Invoke(this, new PowernetEventArgs(Parent));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Triggers event telling power components we have exited any powernets
|
|
||||||
/// </summary>
|
|
||||||
public void DisconnectFromPowernet()
|
|
||||||
{
|
|
||||||
if (Parent == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Parent.NodeList.Remove(this);
|
|
||||||
OnPowernetDisconnect?.Invoke(this, new PowernetEventArgs(Parent));
|
|
||||||
Parent = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PowernetEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
public PowernetEventArgs(Powernet powernet)
|
|
||||||
{
|
|
||||||
Powernet = powernet;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Powernet Powernet { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,292 +0,0 @@
|
|||||||
// Only unused on .NET Core due to KeyValuePair.Deconstruct
|
|
||||||
// ReSharper disable once RedundantUsingDirective
|
|
||||||
using Robust.Shared.Utility;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Robust.Server.Interfaces.GameObjects;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Interfaces.GameObjects.Components;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Serialization;
|
|
||||||
using Robust.Shared.ViewVariables;
|
|
||||||
using Robust.Shared.Map;
|
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Power
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Component that wirelessly connects and powers devices, connects to powernet via node and can be combined with internal storage component
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
[ComponentReference(typeof(PowerDeviceComponent))]
|
|
||||||
public class PowerProviderComponent : PowerDeviceComponent
|
|
||||||
{
|
|
||||||
public override string Name => "PowerProvider";
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override DrawTypes DefaultDrawType => DrawTypes.Node;
|
|
||||||
|
|
||||||
protected override bool SaveLoad => false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Variable that determines the range that the power provider will try to supply power to
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public int PowerRange
|
|
||||||
{
|
|
||||||
get => _range;
|
|
||||||
private set => _range = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int _range = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// List storing all the power devices that we are currently providing power to
|
|
||||||
/// </summary>
|
|
||||||
public SortedSet<PowerDeviceComponent> DeviceLoadList =
|
|
||||||
new SortedSet<PowerDeviceComponent>(new Powernet.DevicePriorityCompare());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// List of devices in range that we "advertised" to.
|
|
||||||
/// </summary>
|
|
||||||
public HashSet<PowerDeviceComponent> AdvertisedDevices = new HashSet<PowerDeviceComponent>();
|
|
||||||
|
|
||||||
public List<PowerDeviceComponent> DepoweredDevices = new List<PowerDeviceComponent>();
|
|
||||||
|
|
||||||
public override Powernet.Priority Priority { get; protected set; } = Powernet.Priority.Provider;
|
|
||||||
|
|
||||||
private bool _mainBreaker = true;
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public bool MainBreaker
|
|
||||||
{
|
|
||||||
get => _mainBreaker;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_mainBreaker == value)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_mainBreaker = value;
|
|
||||||
if (!value)
|
|
||||||
{
|
|
||||||
DepowerAllDevices();
|
|
||||||
Load = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Load = TheoreticalLoad;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private float _theoreticalLoad = 0f;
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
public float TheoreticalLoad
|
|
||||||
{
|
|
||||||
get => _theoreticalLoad;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_theoreticalLoad = value;
|
|
||||||
if (MainBreaker)
|
|
||||||
{
|
|
||||||
Load = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public PowerProviderComponent()
|
|
||||||
{
|
|
||||||
Load = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Shutdown()
|
|
||||||
{
|
|
||||||
base.Shutdown();
|
|
||||||
|
|
||||||
foreach (var device in AdvertisedDevices.ToList())
|
|
||||||
{
|
|
||||||
device.RemoveProvider(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
AdvertisedDevices.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ExposeData(ObjectSerializer serializer)
|
|
||||||
{
|
|
||||||
base.ExposeData(serializer);
|
|
||||||
|
|
||||||
serializer.DataField(ref _range, "range", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal override void ProcessInternalPower(float frametime)
|
|
||||||
{
|
|
||||||
// Right now let's just assume that APCs don't have a power demand themselves and as such they're always marked as powered.
|
|
||||||
InternalPowered = true;
|
|
||||||
if (!Owner.TryGetComponent<PowerStorageComponent>(out var storage))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!MainBreaker)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ExternalPowered)
|
|
||||||
{
|
|
||||||
PowerAllDevices();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (storage.CanDeductCharge(TheoreticalLoad * frametime))
|
|
||||||
{
|
|
||||||
PowerAllDevices();
|
|
||||||
storage.DeductCharge(TheoreticalLoad * frametime);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var remainingEnergy = storage.AvailableCharge(frametime);
|
|
||||||
var usedEnergy = 0f;
|
|
||||||
foreach (var device in DeviceLoadList)
|
|
||||||
{
|
|
||||||
var deviceLoad = device.Load * frametime;
|
|
||||||
if (deviceLoad > remainingEnergy)
|
|
||||||
{
|
|
||||||
device.ExternalPowered = false;
|
|
||||||
DepoweredDevices.Add(device);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!device.ExternalPowered)
|
|
||||||
{
|
|
||||||
DepoweredDevices.Remove(device);
|
|
||||||
device.ExternalPowered = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
usedEnergy += deviceLoad;
|
|
||||||
remainingEnergy -= deviceLoad;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
storage.DeductCharge(usedEnergy);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PowerAllDevices()
|
|
||||||
{
|
|
||||||
foreach (var device in DepoweredDevices)
|
|
||||||
{
|
|
||||||
device.ExternalPowered = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DepoweredDevices.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DepowerAllDevices()
|
|
||||||
{
|
|
||||||
foreach (var device in DeviceLoadList)
|
|
||||||
{
|
|
||||||
device.ExternalPowered = false;
|
|
||||||
DepoweredDevices.Add(device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void PowernetConnect(object sender, PowernetEventArgs eventarg)
|
|
||||||
{
|
|
||||||
base.PowernetConnect(sender, eventarg);
|
|
||||||
|
|
||||||
//Find devices within range to take under our control
|
|
||||||
var entMgr = IoCManager.Resolve<IServerEntityManager>();
|
|
||||||
var position = Owner.GetComponent<ITransformComponent>().WorldPosition;
|
|
||||||
var entities = entMgr.GetEntitiesInRange(Owner, PowerRange)
|
|
||||||
.Where(x => x.HasComponent<PowerDeviceComponent>());
|
|
||||||
|
|
||||||
|
|
||||||
foreach (var entity in entities)
|
|
||||||
{
|
|
||||||
var device = entity.GetComponent<PowerDeviceComponent>();
|
|
||||||
|
|
||||||
//Make sure the device can accept power providers to give it power
|
|
||||||
if (device.DrawType == DrawTypes.Provider || device.DrawType == DrawTypes.Both)
|
|
||||||
{
|
|
||||||
if (!AdvertisedDevices.Contains(device))
|
|
||||||
{
|
|
||||||
device.AddProvider(this);
|
|
||||||
AdvertisedDevices.Add(device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected override void PowernetDisconnect(object sender, PowernetEventArgs eventarg)
|
|
||||||
{
|
|
||||||
base.PowernetDisconnect(sender, eventarg);
|
|
||||||
|
|
||||||
//We don't want to make the devices under us think we're still a valid provider if we have no powernet to connect to
|
|
||||||
foreach (var device in AdvertisedDevices.ToList())
|
|
||||||
{
|
|
||||||
device.RemoveProvider(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
AdvertisedDevices.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Register a continuous load from a device connected to the powernet
|
|
||||||
/// </summary>
|
|
||||||
public void AddDevice(PowerDeviceComponent device)
|
|
||||||
{
|
|
||||||
DeviceLoadList.Add(device);
|
|
||||||
TheoreticalLoad += device.Load;
|
|
||||||
if (!device.Powered)
|
|
||||||
DepoweredDevices.Add(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Update one of the loads from a deviceconnected to the powernet
|
|
||||||
/// </summary>
|
|
||||||
public void UpdateDevice(PowerDeviceComponent device, float oldLoad)
|
|
||||||
{
|
|
||||||
if (DeviceLoadList.Contains(device))
|
|
||||||
{
|
|
||||||
TheoreticalLoad = TheoreticalLoad - oldLoad + device.Load;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove a continuous load from a device connected to the powernet
|
|
||||||
/// </summary>
|
|
||||||
public void RemoveDevice(PowerDeviceComponent device)
|
|
||||||
{
|
|
||||||
if (DeviceLoadList.Contains(device))
|
|
||||||
{
|
|
||||||
TheoreticalLoad -= device.Load;
|
|
||||||
DeviceLoadList.Remove(device);
|
|
||||||
if (DepoweredDevices.Contains(device))
|
|
||||||
DepoweredDevices.Remove(device);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.WarningS("power", "We tried to remove device {0} twice from the same {1}, somehow.",
|
|
||||||
device.Owner, Owner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the device can be serviced by this provider.
|
|
||||||
/// </summary>
|
|
||||||
public bool CanServiceDevice(PowerDeviceComponent device)
|
|
||||||
{
|
|
||||||
// Stops an APC from trying to connect to itself
|
|
||||||
if (this == device)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return device.Owner.Transform.MapID == Owner.Transform.MapID &&
|
|
||||||
(device.Owner.Transform.WorldPosition - Owner.Transform.WorldPosition).Length <= _range;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,179 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
|
||||||
using Content.Shared.GameObjects.Components.Power;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
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
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Stores electrical energy. Used by power cells and SMESes.
|
|
||||||
/// </summary>
|
|
||||||
public abstract class PowerStorageComponent : Component, IExamine
|
|
||||||
{
|
|
||||||
[ViewVariables]
|
|
||||||
public ChargeState LastChargeState { get; private set; } = ChargeState.Still;
|
|
||||||
public DateTime LastChargeStateChange { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Maximum amount of energy the internal battery can store.
|
|
||||||
/// In Joules.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public float Capacity => _capacity;
|
|
||||||
private float _capacity = 10000; // Arbitrary value, replace.
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Energy the battery is currently storing.
|
|
||||||
/// In Joules.
|
|
||||||
/// In most cases you should use <see cref="DeductCharge"/> and <see cref="AddCharge"/> to modify this.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public virtual float Charge
|
|
||||||
{
|
|
||||||
get => _charge;
|
|
||||||
set => _charge = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private float _charge = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Rate at which energy will be taken to charge internal battery.
|
|
||||||
/// In Watts.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public float ChargeRate => _chargeRate;
|
|
||||||
private float _chargeRate = 1000;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Rate at which energy will be distributed to the powernet if needed.
|
|
||||||
/// In Watts.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public float DistributionRate => _distributionRate;
|
|
||||||
private float _distributionRate = 1000;
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
public bool Full => Charge >= Capacity;
|
|
||||||
|
|
||||||
public event Action OnChargeChanged;
|
|
||||||
public override void ExposeData(ObjectSerializer serializer)
|
|
||||||
{
|
|
||||||
base.ExposeData(serializer);
|
|
||||||
|
|
||||||
serializer.DataField(ref _capacity, "capacity", 10000);
|
|
||||||
serializer.DataField(ref _charge, "charge", 0);
|
|
||||||
serializer.DataField(ref _chargeRate, "chargerate", 1000);
|
|
||||||
serializer.DataField(ref _distributionRate, "distributionrate", 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void ChargeChanged()
|
|
||||||
{
|
|
||||||
if (OnChargeChanged != null)
|
|
||||||
{ //Only fire this event if anyone actually subscribes to it
|
|
||||||
OnChargeChanged.Invoke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the storage can supply the amount of charge directly requested
|
|
||||||
/// </summary>
|
|
||||||
public bool CanDeductCharge(float toDeduct)
|
|
||||||
{
|
|
||||||
if (Charge >= toDeduct)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Deducts the requested charge from the energy storage
|
|
||||||
/// </summary>
|
|
||||||
public virtual void DeductCharge(float toDeduct)
|
|
||||||
{
|
|
||||||
_charge = Math.Max(0, Charge - toDeduct);
|
|
||||||
LastChargeState = ChargeState.Discharging;
|
|
||||||
LastChargeStateChange = DateTime.Now;
|
|
||||||
ChargeChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void AddCharge(float charge)
|
|
||||||
{
|
|
||||||
_charge = Math.Min(Capacity, Charge + charge);
|
|
||||||
LastChargeState = ChargeState.Charging;
|
|
||||||
LastChargeStateChange = DateTime.Now;
|
|
||||||
ChargeChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the amount of energy that can be taken in by this storage in the specified amount of time.
|
|
||||||
/// </summary>
|
|
||||||
public float RequestCharge(float frameTime)
|
|
||||||
{
|
|
||||||
return Math.Min(ChargeRate * frameTime, Capacity - Charge);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the amount of energy available for discharge in the specified amount of time.
|
|
||||||
/// </summary>
|
|
||||||
public float AvailableCharge(float frameTime)
|
|
||||||
{
|
|
||||||
return Math.Min(DistributionRate * frameTime, Charge);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tries to deduct a wattage over a certain amount of time.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="wattage">The wattage of the power drain.</param>
|
|
||||||
/// <param name="frameTime">The amount of time in this "frame".</param>
|
|
||||||
/// <returns>True if the amount of energy was deducted, false.</returns>
|
|
||||||
public bool TryDeductWattage(float wattage, float frameTime)
|
|
||||||
{
|
|
||||||
var avail = AvailableCharge(frameTime);
|
|
||||||
if (avail < wattage * frameTime)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeductCharge(wattage * frameTime);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChargeState GetChargeState()
|
|
||||||
{
|
|
||||||
return GetChargeState(TimeSpan.FromSeconds(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChargeState GetChargeState(TimeSpan timeout)
|
|
||||||
{
|
|
||||||
if (LastChargeStateChange + timeout > DateTime.Now)
|
|
||||||
{
|
|
||||||
return LastChargeState;
|
|
||||||
}
|
|
||||||
return ChargeState.Still;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ChargePowerTick(float frameTime)
|
|
||||||
{
|
|
||||||
if (Full)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
AddCharge(RequestCharge(frameTime));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Examine(FormattedMessage message, bool inDetailsRange)
|
|
||||||
{
|
|
||||||
var loc = IoCManager.Resolve<ILocalizationManager>();
|
|
||||||
|
|
||||||
var chargePercent = Math.Round(100*Charge/Capacity, 2);
|
|
||||||
message.AddMarkup(loc.GetString(
|
|
||||||
"[color=yellow]Charge: {0}J / {1}J ({2}%)\nRate: {3}W IN, {4}W OUT[/color]",
|
|
||||||
Math.Round(Charge, 2), Capacity, chargePercent, ChargeRate, DistributionRate));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Serialization;
|
|
||||||
using Robust.Shared.ViewVariables;
|
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Power
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Feeds energy from the powernet and may have the ability to supply back into it
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
[ComponentReference(typeof(PowerStorageComponent))]
|
|
||||||
public class PowerStorageNetComponent : PowerStorageComponent
|
|
||||||
{
|
|
||||||
public override string Name => "PowerStorage";
|
|
||||||
|
|
||||||
private bool _chargePowernet = false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Do we distribute power into the powernet from our stores if the powernet requires it?
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public bool ChargePowernet
|
|
||||||
{
|
|
||||||
get => _chargePowernet;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_chargePowernet = value;
|
|
||||||
if (Owner.TryGetComponent(out PowerNodeComponent node))
|
|
||||||
{
|
|
||||||
node.Parent?.UpdateStorageType(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ExposeData(ObjectSerializer serializer)
|
|
||||||
{
|
|
||||||
base.ExposeData(serializer);
|
|
||||||
|
|
||||||
serializer.DataField(ref _chargePowernet, "chargepowernet", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnAdd()
|
|
||||||
{
|
|
||||||
base.OnAdd();
|
|
||||||
|
|
||||||
if (!Owner.TryGetComponent(out PowerNodeComponent node))
|
|
||||||
{
|
|
||||||
Owner.AddComponent<PowerNodeComponent>();
|
|
||||||
node = Owner.GetComponent<PowerNodeComponent>();
|
|
||||||
}
|
|
||||||
node.OnPowernetConnect += PowernetConnect;
|
|
||||||
node.OnPowernetDisconnect += PowernetDisconnect;
|
|
||||||
node.OnPowernetRegenerate += PowernetRegenerate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnRemove()
|
|
||||||
{
|
|
||||||
if (Owner.TryGetComponent(out PowerNodeComponent node))
|
|
||||||
{
|
|
||||||
if (node.Parent != null)
|
|
||||||
{
|
|
||||||
node.Parent.RemovePowerStorage(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
node.OnPowernetConnect -= PowernetConnect;
|
|
||||||
node.OnPowernetDisconnect -= PowernetDisconnect;
|
|
||||||
node.OnPowernetRegenerate -= PowernetRegenerate;
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnRemove();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Node has become anchored to a powernet
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender"></param>
|
|
||||||
/// <param name="eventarg"></param>
|
|
||||||
private void PowernetConnect(object sender, PowernetEventArgs eventarg)
|
|
||||||
{
|
|
||||||
eventarg.Powernet.AddPowerStorage(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Node has had its powernet regenerated
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender"></param>
|
|
||||||
/// <param name="eventarg"></param>
|
|
||||||
private void PowernetRegenerate(object sender, PowernetEventArgs eventarg)
|
|
||||||
{
|
|
||||||
eventarg.Powernet.AddPowerStorage(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Node has become unanchored from a powernet
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender"></param>
|
|
||||||
/// <param name="eventarg"></param>
|
|
||||||
private void PowernetDisconnect(object sender, PowernetEventArgs eventarg)
|
|
||||||
{
|
|
||||||
eventarg.Powernet.RemovePowerStorage(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using Content.Server.GameObjects.Components.Interactable;
|
|
||||||
using Content.Server.GameObjects.Components.Stack;
|
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
|
||||||
using Content.Shared.GameObjects.Components.Interactable;
|
|
||||||
using Content.Server.Utility;
|
|
||||||
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, IInteractUsing
|
|
||||||
{
|
|
||||||
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 InteractUsing(InteractUsingEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
if (!eventArgs.Using.TryGetComponent(out ToolComponent tool)) return false;
|
|
||||||
if (!tool.UseTool(eventArgs.User, Owner, ToolQuality.Cutting)) return false;
|
|
||||||
|
|
||||||
Owner.Delete();
|
|
||||||
var droppedEnt = Owner.EntityManager.SpawnEntity("CableStack", eventArgs.ClickLocation);
|
|
||||||
|
|
||||||
if (droppedEnt.TryGetComponent<StackComponent>(out var stackComp))
|
|
||||||
stackComp.Count = 1;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,555 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Content.Shared.GameObjects.EntitySystems;
|
|
||||||
using Robust.Shared.GameObjects.Systems;
|
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.ViewVariables;
|
|
||||||
using Robust.Shared.Utility;
|
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Power
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Master class for group of <see cref="PowerTransferComponent"/>, takes in and distributes power via nodes
|
|
||||||
/// </summary>
|
|
||||||
public class Powernet
|
|
||||||
{
|
|
||||||
public Powernet()
|
|
||||||
{
|
|
||||||
var powerSystem = EntitySystem.Get<PowerSystem>();
|
|
||||||
powerSystem.Powernets.Add(this);
|
|
||||||
Uid = powerSystem.NewUid();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Unique identifier per powernet, used for debugging mostly.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public int Uid { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The entities that make up the powernet's physical location and allow powernet connection
|
|
||||||
/// </summary>
|
|
||||||
public readonly List<PowerTransferComponent> WireList = new List<PowerTransferComponent>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Entities that connect directly to the powernet through <see cref="PowerTransferComponent" /> above to add power or add power load
|
|
||||||
/// </summary>
|
|
||||||
public readonly List<PowerNodeComponent> NodeList = new List<PowerNodeComponent>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Subset of nodelist that adds a continuous power supply to the network
|
|
||||||
/// </summary>
|
|
||||||
private readonly Dictionary<PowerGeneratorComponent, float> GeneratorList =
|
|
||||||
new Dictionary<PowerGeneratorComponent, float>();
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
public int GeneratorCount => GeneratorList.Count;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Subset of nodelist that draw power, stores information on current continuous powernet load
|
|
||||||
/// </summary>
|
|
||||||
private readonly SortedSet<PowerDeviceComponent> DeviceLoadList =
|
|
||||||
new SortedSet<PowerDeviceComponent>(new DevicePriorityCompare());
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
public int DeviceCount => DeviceLoadList.Count;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// All the devices that have been depowered by this powernet or depowered prior to being absorted into this powernet
|
|
||||||
/// </summary>
|
|
||||||
private readonly List<PowerDeviceComponent> DepoweredDevices = new List<PowerDeviceComponent>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A list of the energy storage components that will feed the powernet if necessary, and if there is enough power feed itself
|
|
||||||
/// </summary>
|
|
||||||
private readonly List<PowerStorageNetComponent> PowerStorageSupplierList = new List<PowerStorageNetComponent>();
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
public int PowerStorageSupplierCount => PowerStorageSupplierList.Count;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A list of energy storage components that will never feed the powernet, will try to draw energy to feed themselves if possible
|
|
||||||
/// </summary>
|
|
||||||
private readonly List<PowerStorageNetComponent> PowerStorageConsumerList = new List<PowerStorageNetComponent>();
|
|
||||||
|
|
||||||
[ViewVariables]
|
|
||||||
public int PowerStorageConsumerCount => PowerStorageConsumerList.Count;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Static counter of all continuous load placed from devices on this power network.
|
|
||||||
/// In Watts.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public float Load { get; private set; } = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Static counter of all continuous supply from generators on this power network.
|
|
||||||
/// In Watts.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public float Supply { get; private set; } = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Variable that causes powernet to be regenerated from its wires during the next update cycle.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public bool Dirty { get; set; } = false;
|
|
||||||
|
|
||||||
// These are stats for power monitoring equipment such as APCs.
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The total supply that was available to us last tick.
|
|
||||||
/// This does not mean it was used.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public float LastTotalAvailable { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The total power drawn last tick.
|
|
||||||
/// This is how much power was actually, in practice, drawn.
|
|
||||||
/// Not how much SHOULD have been drawn.
|
|
||||||
/// If avail < demand, this will be just <= than the actual avail
|
|
||||||
/// (e.g. if all machines need 100 W but there's 20 W excess, the 20 W will be avail but not drawn.)
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public float LastTotalDraw { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The amount of power that was demanded last tick.
|
|
||||||
/// This does not mean it was full filled in practice.
|
|
||||||
/// This does not include the demand from storage suppliers until the suppliers are actually capable of drawing power.
|
|
||||||
/// As such, this will quite abruptly shoot up if available rises to cover supplier charge demand too.
|
|
||||||
/// </summary>
|
|
||||||
/// <seealso cref="LastTotalDemandWithSuppliers"/>
|
|
||||||
[ViewVariables]
|
|
||||||
public float LastTotalDemand { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The amount of power that was demanded last tick, ALWAYS including storage supplier draw.
|
|
||||||
/// This does not mean it was full filled in practice.
|
|
||||||
/// See <see cref="LastTotalDemand"/> for the difference.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public float LastTotalDemandWithSuppliers { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The amount of power that we are lacking to properly power everything (excluding storage supplier charging).
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public float Lack => Math.Max(0, LastTotalDemand - LastTotalAvailable);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The total amount of power that wasn't used last tick.
|
|
||||||
/// This does not necessarily mean it went to waste, unused supply from storage is also counted.
|
|
||||||
/// It is ALSO not implied that if this is > 0, that we have sufficient power for everything.
|
|
||||||
/// See the doc comment on <see cref="LastTotalDraw"/>.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables]
|
|
||||||
public float Excess => Math.Max(0, LastTotalAvailable - LastTotalDraw);
|
|
||||||
|
|
||||||
public void Update(float frameTime)
|
|
||||||
{
|
|
||||||
// The amount of energy that is supplied from generators that do not care if it's used or not.
|
|
||||||
var activeSupply = Supply * frameTime;
|
|
||||||
// The total load we need to fill for machines.
|
|
||||||
var activeLoad = Load * frameTime;
|
|
||||||
|
|
||||||
// The total load from storage consumers (batteries that do not supply like an SMES)
|
|
||||||
float storageConsumerDemand = 0;
|
|
||||||
foreach (var supply in PowerStorageConsumerList)
|
|
||||||
{
|
|
||||||
storageConsumerDemand += supply.RequestCharge(frameTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The total supply from storage suppliers.
|
|
||||||
float storageSupply = 0;
|
|
||||||
// The total load from storage suppliers (batteries that DO supply like an SMES)
|
|
||||||
float storageSupplierDemand = 0;
|
|
||||||
foreach (var supply in PowerStorageSupplierList)
|
|
||||||
{
|
|
||||||
storageSupply += supply.AvailableCharge(frameTime);
|
|
||||||
storageSupplierDemand += supply.RequestCharge(frameTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
LastTotalAvailable = (storageSupply + activeSupply) / frameTime;
|
|
||||||
LastTotalDemandWithSuppliers = (activeLoad + storageConsumerDemand + storageSupplierDemand) / frameTime;
|
|
||||||
|
|
||||||
// The happy case.
|
|
||||||
// If we have enough power to feed all load and storage demand, then feed everything
|
|
||||||
if (activeSupply > activeLoad + storageConsumerDemand + storageSupplierDemand)
|
|
||||||
{
|
|
||||||
PowerAllDevices();
|
|
||||||
ChargeStorageConsumers(frameTime);
|
|
||||||
ChargeStorageSuppliers(frameTime);
|
|
||||||
LastTotalDraw = LastTotalDemand = LastTotalDemandWithSuppliers;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LastTotalDemand = (activeLoad + storageConsumerDemand) / frameTime;
|
|
||||||
|
|
||||||
// We don't have enough power for the storage powernet suppliers, ignore powering them
|
|
||||||
// TODO: This is technically incorrect, it's totally possible to power *some* suppliers here,
|
|
||||||
// just not all.
|
|
||||||
if (activeSupply > activeLoad + storageConsumerDemand)
|
|
||||||
{
|
|
||||||
PowerAllDevices();
|
|
||||||
ChargeStorageConsumers(frameTime);
|
|
||||||
LastTotalDraw = LastTotalDemand;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The complex case: There is too little power to power everything without using storage suppliers (SMES).
|
|
||||||
// We have to keep track of power draw as to not incorrectly detract too much from storage suppliers.
|
|
||||||
|
|
||||||
// Calculate the total potential supply, then go through every normal load and detract.
|
|
||||||
var totalRemaining = activeSupply + storageSupply;
|
|
||||||
foreach (var device in DeviceLoadList)
|
|
||||||
{
|
|
||||||
var deviceLoad = device.Load * frameTime;
|
|
||||||
if (deviceLoad > totalRemaining)
|
|
||||||
{
|
|
||||||
device.ExternalPowered = false;
|
|
||||||
DepoweredDevices.Add(device);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
totalRemaining -= deviceLoad;
|
|
||||||
if (!device.ExternalPowered)
|
|
||||||
{
|
|
||||||
DepoweredDevices.Remove(device);
|
|
||||||
device.ExternalPowered = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (totalRemaining > 0)
|
|
||||||
{
|
|
||||||
// What we have left (if any) goes into storage consumers.
|
|
||||||
foreach (var consumer in PowerStorageConsumerList)
|
|
||||||
{
|
|
||||||
if (totalRemaining < 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
var demand = consumer.RequestCharge(frameTime);
|
|
||||||
if (demand == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var taken = Math.Min(demand, totalRemaining);
|
|
||||||
totalRemaining -= taken;
|
|
||||||
consumer.AddCharge(taken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LastTotalDraw = (activeSupply + storageSupply - totalRemaining) / frameTime;
|
|
||||||
|
|
||||||
// activeSupply is free to use, but storageSupply is not.
|
|
||||||
// Calculate how much of storageSupply, and deduct it from the storage suppliers.
|
|
||||||
var supplierUsed = storageSupply - totalRemaining;
|
|
||||||
|
|
||||||
// And deduct!
|
|
||||||
foreach (var supplier in PowerStorageSupplierList)
|
|
||||||
{
|
|
||||||
var load = supplier.AvailableCharge(frameTime);
|
|
||||||
if (load == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var added = Math.Min(load, supplierUsed);
|
|
||||||
supplierUsed -= added;
|
|
||||||
supplier.DeductCharge(added);
|
|
||||||
if (supplierUsed <= 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void PowerAllDevices()
|
|
||||||
{
|
|
||||||
foreach (var device in DepoweredDevices)
|
|
||||||
{
|
|
||||||
device.ExternalPowered = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DepoweredDevices.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ChargeStorageConsumers(float frametime)
|
|
||||||
{
|
|
||||||
foreach (var storage in PowerStorageConsumerList)
|
|
||||||
{
|
|
||||||
storage.ChargePowerTick(frametime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ChargeStorageSuppliers(float frametime)
|
|
||||||
{
|
|
||||||
foreach (var storage in PowerStorageSupplierList)
|
|
||||||
{
|
|
||||||
storage.ChargePowerTick(frametime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Kills a powernet after it is marked dirty and its component have already been regenerated by the powernet system
|
|
||||||
/// </summary>
|
|
||||||
public void DirtyKill()
|
|
||||||
{
|
|
||||||
WireList.Clear();
|
|
||||||
while (NodeList.Count != 0)
|
|
||||||
{
|
|
||||||
NodeList[0].DisconnectFromPowernet();
|
|
||||||
}
|
|
||||||
|
|
||||||
GeneratorList.Clear();
|
|
||||||
DeviceLoadList.Clear();
|
|
||||||
DepoweredDevices.Clear();
|
|
||||||
PowerStorageSupplierList.Clear();
|
|
||||||
PowerStorageConsumerList.Clear();
|
|
||||||
|
|
||||||
RemoveFromSystem();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Combines two powernets when they connect via powertransfer components
|
|
||||||
/// </summary>
|
|
||||||
public void MergePowernets(Powernet toMerge)
|
|
||||||
{
|
|
||||||
//TODO: load balance reconciliation between powernets on merge tick here
|
|
||||||
|
|
||||||
foreach (var wire in toMerge.WireList)
|
|
||||||
{
|
|
||||||
wire.Parent = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
WireList.AddRange(toMerge.WireList);
|
|
||||||
toMerge.WireList.Clear();
|
|
||||||
|
|
||||||
foreach (var node in toMerge.NodeList)
|
|
||||||
{
|
|
||||||
node.Parent = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeList.AddRange(toMerge.NodeList);
|
|
||||||
toMerge.NodeList.Clear();
|
|
||||||
|
|
||||||
foreach (var generator in toMerge.GeneratorList)
|
|
||||||
{
|
|
||||||
GeneratorList.Add(generator.Key, generator.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Supply += toMerge.Supply;
|
|
||||||
toMerge.Supply = 0;
|
|
||||||
toMerge.GeneratorList.Clear();
|
|
||||||
|
|
||||||
foreach (var device in toMerge.DeviceLoadList)
|
|
||||||
{
|
|
||||||
DeviceLoadList.Add(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
Load += toMerge.Load;
|
|
||||||
toMerge.Load = 0;
|
|
||||||
toMerge.DeviceLoadList.Clear();
|
|
||||||
|
|
||||||
DepoweredDevices.AddRange(toMerge.DepoweredDevices);
|
|
||||||
toMerge.DepoweredDevices.Clear();
|
|
||||||
|
|
||||||
PowerStorageSupplierList.AddRange(toMerge.PowerStorageSupplierList);
|
|
||||||
toMerge.PowerStorageSupplierList.Clear();
|
|
||||||
|
|
||||||
PowerStorageConsumerList.AddRange(toMerge.PowerStorageConsumerList);
|
|
||||||
toMerge.PowerStorageConsumerList.Clear();
|
|
||||||
|
|
||||||
toMerge.RemoveFromSystem();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes reference from the powernets list on the powernet system
|
|
||||||
/// </summary>
|
|
||||||
private void RemoveFromSystem()
|
|
||||||
{
|
|
||||||
EntitySystem.Get<PowerSystem>().Powernets.Remove(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Registration
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Register a continuous load from a device connected to the powernet
|
|
||||||
/// </summary>
|
|
||||||
public void AddDevice(PowerDeviceComponent device)
|
|
||||||
{
|
|
||||||
DeviceLoadList.Add(device);
|
|
||||||
Load += device.Load;
|
|
||||||
if (!device.Powered)
|
|
||||||
DepoweredDevices.Add(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Update one of the loads from a deviceconnected to the powernet
|
|
||||||
/// </summary>
|
|
||||||
public void UpdateDevice(PowerDeviceComponent device, float oldLoad)
|
|
||||||
{
|
|
||||||
if (DeviceLoadList.Contains(device))
|
|
||||||
{
|
|
||||||
Load -= oldLoad;
|
|
||||||
Load += device.Load;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns whether or not a power device is in this powernet's load list.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="device">The device to check for.</param>
|
|
||||||
/// <returns>True if the device is in the load list, false otherwise.</returns>
|
|
||||||
public bool HasDevice(PowerDeviceComponent device)
|
|
||||||
{
|
|
||||||
return DeviceLoadList.Contains(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove a continuous load from a device connected to the powernet
|
|
||||||
/// </summary>
|
|
||||||
public void RemoveDevice(PowerDeviceComponent device)
|
|
||||||
{
|
|
||||||
if (DeviceLoadList.Contains(device))
|
|
||||||
{
|
|
||||||
Load -= device.Load;
|
|
||||||
DeviceLoadList.Remove(device);
|
|
||||||
if (DepoweredDevices.Contains(device))
|
|
||||||
DepoweredDevices.Remove(device);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.WarningS("power", "We tried to remove device {0} twice from {1}, somehow.", device.Owner, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Register a power supply from a generator connected to the powernet
|
|
||||||
/// </summary>
|
|
||||||
public void AddGenerator(PowerGeneratorComponent generator)
|
|
||||||
{
|
|
||||||
GeneratorList.Add(generator, generator.Supply);
|
|
||||||
Supply += generator.Supply;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Update the value supplied from a generator connected to the powernet
|
|
||||||
/// </summary>
|
|
||||||
public void UpdateGenerator(PowerGeneratorComponent generator)
|
|
||||||
{
|
|
||||||
if (GeneratorList.ContainsKey(generator))
|
|
||||||
{
|
|
||||||
Supply -= GeneratorList[generator];
|
|
||||||
GeneratorList[generator] = generator.Supply;
|
|
||||||
Supply += generator.Supply;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove a power supply from a generator connected to the powernet
|
|
||||||
/// </summary>
|
|
||||||
public void RemoveGenerator(PowerGeneratorComponent generator)
|
|
||||||
{
|
|
||||||
if (GeneratorList.ContainsKey(generator))
|
|
||||||
{
|
|
||||||
Supply -= GeneratorList[generator];
|
|
||||||
GeneratorList.Remove(generator);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.WarningS("power", "We tried to remove generator {0} twice from {1}, somehow.", generator.Owner,
|
|
||||||
this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Register a power supply from a generator connected to the powernet
|
|
||||||
/// </summary>
|
|
||||||
public void AddPowerStorage(PowerStorageNetComponent storage)
|
|
||||||
{
|
|
||||||
if (storage.ChargePowernet)
|
|
||||||
PowerStorageSupplierList.Add(storage);
|
|
||||||
else
|
|
||||||
PowerStorageConsumerList.Add(storage);
|
|
||||||
}
|
|
||||||
|
|
||||||
//How do I even call this? TODO: fix
|
|
||||||
public void UpdateStorageType(PowerStorageNetComponent storage)
|
|
||||||
{
|
|
||||||
//If our chargepowernet settings change we need to tell the powernet of this new setting and remove traces of our old setting
|
|
||||||
if (PowerStorageSupplierList.Contains(storage))
|
|
||||||
PowerStorageSupplierList.Remove(storage);
|
|
||||||
if (PowerStorageConsumerList.Contains(storage))
|
|
||||||
PowerStorageConsumerList.Remove(storage);
|
|
||||||
|
|
||||||
//Apply new setting
|
|
||||||
if (storage.ChargePowernet)
|
|
||||||
PowerStorageSupplierList.Add(storage);
|
|
||||||
else
|
|
||||||
PowerStorageConsumerList.Add(storage);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Remove a power supply from a generator connected to the powernet
|
|
||||||
/// </summary>
|
|
||||||
public void RemovePowerStorage(PowerStorageNetComponent storage)
|
|
||||||
{
|
|
||||||
if (PowerStorageSupplierList.Contains(storage))
|
|
||||||
{
|
|
||||||
PowerStorageSupplierList.Remove(storage);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PowerStorageConsumerList.Contains(storage))
|
|
||||||
{
|
|
||||||
PowerStorageSupplierList.Remove(storage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Registration
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return $"Powernet {Uid}";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Priority that a device will receive power if powernet cannot supply every device
|
|
||||||
/// </summary>
|
|
||||||
public enum Priority
|
|
||||||
{
|
|
||||||
Necessary = 0,
|
|
||||||
High = 1,
|
|
||||||
Medium = 2,
|
|
||||||
Low = 3,
|
|
||||||
Provider = 4,
|
|
||||||
Unnecessary = 5
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Comparer that keeps the device dictionary sorted by powernet priority
|
|
||||||
/// </summary>
|
|
||||||
public class DevicePriorityCompare : IComparer<PowerDeviceComponent>
|
|
||||||
{
|
|
||||||
public int Compare(PowerDeviceComponent x, PowerDeviceComponent y)
|
|
||||||
{
|
|
||||||
int compare = y.Priority.CompareTo(x.Priority);
|
|
||||||
|
|
||||||
//If the comparer returns 0 sortedset will believe it is a duplicate and return 0, so return 1 instead
|
|
||||||
if (compare == 0)
|
|
||||||
{
|
|
||||||
return y.Owner.Uid.CompareTo(x.Owner.Uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
return compare;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
using Content.Shared.GameObjects.Components.Power;
|
|
||||||
using Content.Shared.Utility;
|
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Power
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Handles the "user-facing" side of the actual SMES object.
|
|
||||||
/// This is operations that are specific to the SMES, like UI and visuals.
|
|
||||||
/// Code interfacing with the powernet is handled in <see cref="PowerStorageComponent" />.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public class SmesComponent : Component
|
|
||||||
{
|
|
||||||
public override string Name => "Smes";
|
|
||||||
|
|
||||||
PowerStorageComponent Storage;
|
|
||||||
AppearanceComponent Appearance;
|
|
||||||
|
|
||||||
int LastChargeLevel = 0;
|
|
||||||
ChargeState LastChargeState;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
Storage = Owner.GetComponent<PowerStorageComponent>();
|
|
||||||
Appearance = Owner.GetComponent<AppearanceComponent>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnUpdate()
|
|
||||||
{
|
|
||||||
var newLevel = CalcChargeLevel();
|
|
||||||
if (newLevel != LastChargeLevel)
|
|
||||||
{
|
|
||||||
LastChargeLevel = newLevel;
|
|
||||||
Appearance.SetData(SmesVisuals.LastChargeLevel, newLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
var newState = Storage.GetChargeState();
|
|
||||||
if (newState != LastChargeState)
|
|
||||||
{
|
|
||||||
LastChargeState = newState;
|
|
||||||
Appearance.SetData(SmesVisuals.LastChargeState, newState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int CalcChargeLevel()
|
|
||||||
{
|
|
||||||
return ContentHelpers.RoundToLevels(Storage.Charge, Storage.Capacity, 6);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
58
Content.Server/GameObjects/Components/Power/WireComponent.cs
Normal file
58
Content.Server/GameObjects/Components/Power/WireComponent.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using Content.Server.GameObjects.Components.Interactable;
|
||||||
|
using Content.Server.GameObjects.Components.Stack;
|
||||||
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
|
using Content.Shared.GameObjects.Components.Interactable;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Power
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Allows the attached entity to be destroyed by a cutting tool, dropping a piece of wire.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public class WireComponent : Component, IInteractUsing
|
||||||
|
{
|
||||||
|
public override string Name => "Wire";
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private string _wireDroppedOnCutPrototype;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checked by <see cref="WirePlacerComponent"/> to determine if there is
|
||||||
|
/// already a wire of a type on a tile.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public WireType WireType => _wireType;
|
||||||
|
private WireType _wireType;
|
||||||
|
|
||||||
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
|
{
|
||||||
|
base.ExposeData(serializer);
|
||||||
|
serializer.DataField(ref _wireDroppedOnCutPrototype, "wireDroppedOnCutPrototype", "HVWireStack1");
|
||||||
|
serializer.DataField(ref _wireType, "wireType", WireType.HighVoltage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool InteractUsing(InteractUsingEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
if (!eventArgs.Using.TryGetComponent(out ToolComponent tool)) return false;
|
||||||
|
if (!tool.UseTool(eventArgs.User, Owner, ToolQuality.Cutting)) return false;
|
||||||
|
|
||||||
|
Owner.Delete();
|
||||||
|
var droppedEnt = Owner.EntityManager.SpawnEntity(_wireDroppedOnCutPrototype, eventArgs.ClickLocation);
|
||||||
|
|
||||||
|
if (droppedEnt.TryGetComponent<StackComponent>(out var stackComp))
|
||||||
|
stackComp.Count = 1;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum WireType
|
||||||
|
{
|
||||||
|
HighVoltage,
|
||||||
|
MediumVoltage,
|
||||||
|
Apc,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,18 @@
|
|||||||
using Content.Server.GameObjects.Components.Stack;
|
using Content.Server.GameObjects.Components.NodeContainer;
|
||||||
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
|
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||||
|
using Content.Server.GameObjects.Components.Stack;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
using Content.Server.Utility;
|
using Content.Server.Utility;
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Server.Interfaces.GameObjects;
|
using Robust.Server.Interfaces.GameObjects;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameObjects.Components.Transform;
|
using Robust.Shared.GameObjects.Components.Transform;
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
|
||||||
using Robust.Shared.Interfaces.Map;
|
using Robust.Shared.Interfaces.Map;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Power
|
namespace Content.Server.GameObjects.Components.Power
|
||||||
{
|
{
|
||||||
@@ -23,46 +27,39 @@ namespace Content.Server.GameObjects.Components.Power
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string Name => "WirePlacer";
|
public override string Name => "WirePlacer";
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private string _wirePrototypeID;
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
private WireType _blockingWireType;
|
||||||
|
|
||||||
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
|
{
|
||||||
|
base.ExposeData(serializer);
|
||||||
|
serializer.DataField(ref _wirePrototypeID, "wirePrototypeID", "HVWire");
|
||||||
|
serializer.DataField(ref _blockingWireType, "blockingWireType", WireType.HighVoltage);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void AfterInteract(AfterInteractEventArgs eventArgs)
|
public void AfterInteract(AfterInteractEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
|
if (!InteractionChecks.InRangeUnobstructed(eventArgs)) return;
|
||||||
|
|
||||||
if(!_mapManager.TryGetGrid(eventArgs.ClickLocation.GridID, out var grid))
|
if(!_mapManager.TryGetGrid(eventArgs.ClickLocation.GridID, out var grid))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var snapPos = grid.SnapGridCellFor(eventArgs.ClickLocation, SnapGridOffset.Center);
|
var snapPos = grid.SnapGridCellFor(eventArgs.ClickLocation, SnapGridOffset.Center);
|
||||||
var snapCell = grid.GetSnapGridCell(snapPos, SnapGridOffset.Center);
|
var snapCell = grid.GetSnapGridCell(snapPos, SnapGridOffset.Center);
|
||||||
|
|
||||||
if(grid.GetTileRef(snapPos).Tile.IsEmpty)
|
if(grid.GetTileRef(snapPos).Tile.IsEmpty)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var found = false;
|
|
||||||
foreach (var snapComp in snapCell)
|
foreach (var snapComp in snapCell)
|
||||||
{
|
{
|
||||||
if (!snapComp.Owner.HasComponent<PowerTransferComponent>())
|
if (snapComp.Owner.TryGetComponent<WireComponent>(out var wire) && wire.WireType == _blockingWireType)
|
||||||
continue;
|
{
|
||||||
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found)
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
bool hasItemSpriteComp = Owner.TryGetComponent(out SpriteComponent itemSpriteComp);
|
}
|
||||||
|
|
||||||
if (Owner.TryGetComponent(out StackComponent stack) && !stack.Use(1))
|
if (Owner.TryGetComponent(out StackComponent stack) && !stack.Use(1))
|
||||||
return;
|
return;
|
||||||
|
_entityManager.SpawnEntity(_wirePrototypeID, grid.GridTileToLocal(snapPos));
|
||||||
GridCoordinates coordinates = grid.GridTileToLocal(snapPos);
|
|
||||||
var newWire = _entityManager.SpawnEntity("Wire", coordinates);
|
|
||||||
if (newWire.TryGetComponent(out SpriteComponent wireSpriteComp) && hasItemSpriteComp)
|
|
||||||
{
|
|
||||||
wireSpriteComp.Color = itemSpriteComp.Color;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: There is no way to set this wire as above or below the floor
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ using Robust.Server.Interfaces.Player;
|
|||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Timers;
|
using Robust.Shared.Timers;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Research
|
namespace Content.Server.GameObjects.Components.Research
|
||||||
{
|
{
|
||||||
@@ -47,8 +48,8 @@ namespace Content.Server.GameObjects.Components.Research
|
|||||||
}
|
}
|
||||||
|
|
||||||
private LatheRecipePrototype _producingRecipe = null;
|
private LatheRecipePrototype _producingRecipe = null;
|
||||||
private PowerDeviceComponent _powerDevice;
|
private PowerReceiverComponent _powerReceiver;
|
||||||
private bool Powered => _powerDevice.Powered;
|
private bool Powered => _powerReceiver.Powered;
|
||||||
|
|
||||||
private static readonly TimeSpan InsertionTime = TimeSpan.FromSeconds(0.9f);
|
private static readonly TimeSpan InsertionTime = TimeSpan.FromSeconds(0.9f);
|
||||||
|
|
||||||
@@ -57,7 +58,7 @@ namespace Content.Server.GameObjects.Components.Research
|
|||||||
base.Initialize();
|
base.Initialize();
|
||||||
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(LatheUiKey.Key);
|
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(LatheUiKey.Key);
|
||||||
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
|
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
|
||||||
_powerDevice = Owner.GetComponent<PowerDeviceComponent>();
|
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
|
||||||
_appearance = Owner.GetComponent<AppearanceComponent>();
|
_appearance = Owner.GetComponent<AppearanceComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Server.GameObjects.Components.Power;
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
|
using Content.Server.GameObjects.Components.Power;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
using Content.Server.Utility;
|
using Content.Server.Utility;
|
||||||
using Content.Shared.Audio;
|
using Content.Shared.Audio;
|
||||||
@@ -31,10 +32,10 @@ namespace Content.Server.GameObjects.Components.Research
|
|||||||
|
|
||||||
private BoundUserInterface _userInterface;
|
private BoundUserInterface _userInterface;
|
||||||
private ResearchClientComponent _client;
|
private ResearchClientComponent _client;
|
||||||
private PowerDeviceComponent _powerDevice;
|
private PowerReceiverComponent _powerReceiver;
|
||||||
private const string _soundCollectionName = "keyboard";
|
private const string _soundCollectionName = "keyboard";
|
||||||
|
|
||||||
private bool Powered => _powerDevice.Powered;
|
private bool Powered => _powerReceiver.Powered;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -42,7 +43,7 @@ namespace Content.Server.GameObjects.Components.Research
|
|||||||
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(ResearchConsoleUiKey.Key);
|
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(ResearchConsoleUiKey.Key);
|
||||||
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
|
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
|
||||||
_client = Owner.GetComponent<ResearchClientComponent>();
|
_client = Owner.GetComponent<ResearchClientComponent>();
|
||||||
_powerDevice = Owner.GetComponent<PowerDeviceComponent>();
|
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage message)
|
private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage message)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
using Content.Server.GameObjects.Components.Power;
|
using Content.Server.GameObjects.Components.Power;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -14,7 +15,7 @@ namespace Content.Server.GameObjects.Components.Research
|
|||||||
|
|
||||||
private int _pointsPerSecond;
|
private int _pointsPerSecond;
|
||||||
private bool _active;
|
private bool _active;
|
||||||
private PowerDeviceComponent _powerDevice;
|
private PowerReceiverComponent _powerReceiver;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public int PointsPerSecond
|
public int PointsPerSecond
|
||||||
@@ -33,13 +34,13 @@ namespace Content.Server.GameObjects.Components.Research
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether this can be used to produce research points.
|
/// Whether this can be used to produce research points.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>If no <see cref="PowerDeviceComponent"/> is found, it's assumed power is not required.</remarks>
|
/// <remarks>If no <see cref="PowerReceiverComponent"/> is found, it's assumed power is not required.</remarks>
|
||||||
public bool CanProduce => Active && (_powerDevice is null || _powerDevice.Powered);
|
public bool CanProduce => Active && (_powerReceiver is null || _powerReceiver.Powered);
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
Owner.TryGetComponent(out _powerDevice);
|
Owner.TryGetComponent(out _powerReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ExposeData(ObjectSerializer serializer)
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using Robust.Shared.IoC;
|
|||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.Components.Research
|
namespace Content.Server.GameObjects.Components.Research
|
||||||
{
|
{
|
||||||
@@ -65,11 +66,11 @@ namespace Content.Server.GameObjects.Components.Research
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <remarks>If no <see cref="PowerDeviceComponent"/> is found, it's assumed power is not required.</remarks>
|
/// <remarks>If no <see cref="PowerReceiverComponent"/> is found, it's assumed power is not required.</remarks>
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public bool CanRun => _powerDevice is null || _powerDevice.Powered;
|
public bool CanRun => _powerReceiver is null || _powerReceiver.Powered;
|
||||||
|
|
||||||
private PowerDeviceComponent _powerDevice;
|
private PowerReceiverComponent _powerReceiver;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -77,7 +78,7 @@ namespace Content.Server.GameObjects.Components.Research
|
|||||||
Id = ServerCount++;
|
Id = ServerCount++;
|
||||||
EntitySystem.Get<ResearchSystem>()?.RegisterServer(this);
|
EntitySystem.Get<ResearchSystem>()?.RegisterServer(this);
|
||||||
Database = Owner.GetComponent<TechnologyDatabaseComponent>();
|
Database = Owner.GetComponent<TechnologyDatabaseComponent>();
|
||||||
Owner.TryGetComponent(out _powerDevice);
|
Owner.TryGetComponent(out _powerReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.GameObjects.Components.Power;
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
using Content.Server.GameObjects.EntitySystems;
|
using Content.Server.GameObjects.EntitySystems;
|
||||||
using Content.Server.Utility;
|
using Content.Server.Utility;
|
||||||
using Content.Shared.GameObjects.Components.VendingMachines;
|
using Content.Shared.GameObjects.Components.VendingMachines;
|
||||||
@@ -31,7 +31,7 @@ namespace Content.Server.GameObjects.Components.VendingMachines
|
|||||||
#pragma warning restore 649
|
#pragma warning restore 649
|
||||||
private AppearanceComponent _appearance;
|
private AppearanceComponent _appearance;
|
||||||
private BoundUserInterface _userInterface;
|
private BoundUserInterface _userInterface;
|
||||||
private PowerDeviceComponent _powerDevice;
|
private PowerReceiverComponent _powerReceiver;
|
||||||
|
|
||||||
private bool _ejecting = false;
|
private bool _ejecting = false;
|
||||||
private TimeSpan _animationDuration = TimeSpan.Zero;
|
private TimeSpan _animationDuration = TimeSpan.Zero;
|
||||||
@@ -39,7 +39,7 @@ namespace Content.Server.GameObjects.Components.VendingMachines
|
|||||||
private string _description;
|
private string _description;
|
||||||
private string _spriteName;
|
private string _spriteName;
|
||||||
|
|
||||||
private bool Powered => _powerDevice.Powered;
|
private bool Powered => _powerReceiver.Powered;
|
||||||
private bool _broken = false;
|
private bool _broken = false;
|
||||||
|
|
||||||
public void Activate(ActivateEventArgs eventArgs)
|
public void Activate(ActivateEventArgs eventArgs)
|
||||||
@@ -103,16 +103,17 @@ namespace Content.Server.GameObjects.Components.VendingMachines
|
|||||||
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
|
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
|
||||||
.GetBoundUserInterface(VendingMachineUiKey.Key);
|
.GetBoundUserInterface(VendingMachineUiKey.Key);
|
||||||
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
|
_userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage;
|
||||||
_powerDevice = Owner.GetComponent<PowerDeviceComponent>();
|
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
|
||||||
_powerDevice.OnPowerStateChanged += UpdatePower;
|
_powerReceiver.OnPowerStateChanged += UpdatePower;
|
||||||
|
TrySetVisualState(_powerReceiver.Powered ? VendingMachineVisualState.Normal : VendingMachineVisualState.Off);
|
||||||
InitializeFromPrototype();
|
InitializeFromPrototype();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnRemove()
|
public override void OnRemove()
|
||||||
{
|
{
|
||||||
_appearance = null;
|
_appearance = null;
|
||||||
_powerDevice.OnPowerStateChanged -= UpdatePower;
|
_powerReceiver.OnPowerStateChanged -= UpdatePower;
|
||||||
_powerDevice = null;
|
_powerReceiver = null;
|
||||||
base.OnRemove();
|
base.OnRemove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,13 +57,13 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
|
|||||||
public bool Activated => _activated;
|
public bool Activated => _activated;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
private PowerCellComponent Cell
|
private BatteryComponent Cell
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_cellContainer.ContainedEntity == null) return null;
|
if (_cellContainer.ContainedEntity == null) return null;
|
||||||
|
|
||||||
_cellContainer.ContainedEntity.TryGetComponent(out PowerCellComponent cell);
|
_cellContainer.ContainedEntity.TryGetComponent(out BatteryComponent cell);
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,9 +88,12 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
|
|||||||
public override bool OnHitEntities(IReadOnlyList<IEntity> entities)
|
public override bool OnHitEntities(IReadOnlyList<IEntity> entities)
|
||||||
{
|
{
|
||||||
var cell = Cell;
|
var cell = Cell;
|
||||||
if (!Activated || entities.Count == 0 || cell == null || !cell.CanDeductCharge(EnergyPerUse))
|
if (!Activated || entities.Count == 0 || cell == null)
|
||||||
return false;
|
return false;
|
||||||
|
if (!cell.TryUseCharge(EnergyPerUse))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
EntitySystem.Get<AudioSystem>().PlayAtCoords("/Audio/weapons/egloves.ogg", Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
|
EntitySystem.Get<AudioSystem>().PlayAtCoords("/Audio/weapons/egloves.ogg", Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
|
||||||
|
|
||||||
foreach (var entity in entities)
|
foreach (var entity in entities)
|
||||||
@@ -108,9 +111,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
|
|||||||
else
|
else
|
||||||
stunnable.Slowdown(_slowdownTime);
|
stunnable.Slowdown(_slowdownTime);
|
||||||
}
|
}
|
||||||
|
if(cell.CurrentCharge < EnergyPerUse)
|
||||||
cell.DeductCharge(EnergyPerUse);
|
|
||||||
if(cell.Charge < EnergyPerUse)
|
|
||||||
{
|
{
|
||||||
EntitySystem.Get<AudioSystem>().PlayAtCoords(AudioHelpers.GetRandomFileFromSoundCollection("sparks"), Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
|
EntitySystem.Get<AudioSystem>().PlayAtCoords(AudioHelpers.GetRandomFileFromSoundCollection("sparks"), Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
|
||||||
TurnOff();
|
TurnOff();
|
||||||
@@ -169,7 +170,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cell.Charge < EnergyPerUse)
|
if (cell.CurrentCharge < EnergyPerUse)
|
||||||
{
|
{
|
||||||
EntitySystem.Get<AudioSystem>().PlayAtCoords("/Audio/machines/button.ogg", Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
|
EntitySystem.Get<AudioSystem>().PlayAtCoords("/Audio/machines/button.ogg", Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
|
||||||
_notifyManager.PopupMessage(Owner, user, _localizationManager.GetString("Dead cell..."));
|
_notifyManager.PopupMessage(Owner, user, _localizationManager.GetString("Dead cell..."));
|
||||||
@@ -192,7 +193,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
|
|||||||
|
|
||||||
public bool InteractUsing(InteractUsingEventArgs eventArgs)
|
public bool InteractUsing(InteractUsingEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
if (!eventArgs.Using.HasComponent<PowerCellComponent>()) return false;
|
if (!eventArgs.Using.HasComponent<BatteryComponent>()) return false;
|
||||||
|
|
||||||
if (Cell != null) return false;
|
if (Cell != null) return false;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Content.Server.GameObjects.Components.Power;
|
using Content.Server.GameObjects.Components.Power;
|
||||||
using Content.Server.GameObjects.Components.Projectiles;
|
using Content.Server.GameObjects.Components.Projectiles;
|
||||||
@@ -33,7 +33,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
|||||||
[ViewVariables] private string _ammoPrototype;
|
[ViewVariables] private string _ammoPrototype;
|
||||||
|
|
||||||
[ViewVariables] public IEntity PowerCellEntity => _powerCellContainer.ContainedEntity;
|
[ViewVariables] public IEntity PowerCellEntity => _powerCellContainer.ContainedEntity;
|
||||||
public PowerCellComponent PowerCell => _powerCellContainer.ContainedEntity.GetComponent<PowerCellComponent>();
|
public BatteryComponent PowerCell => _powerCellContainer.ContainedEntity.GetComponent<BatteryComponent>();
|
||||||
private ContainerSlot _powerCellContainer;
|
private ContainerSlot _powerCellContainer;
|
||||||
private ContainerSlot _ammoContainer;
|
private ContainerSlot _ammoContainer;
|
||||||
private string _powerCellPrototype;
|
private string _powerCellPrototype;
|
||||||
@@ -50,7 +50,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (int) Math.Ceiling(powerCell.GetComponent<PowerCellComponent>().Charge / _baseFireCost);
|
return (int) Math.Ceiling(powerCell.GetComponent<BatteryComponent>().CurrentCharge / _baseFireCost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (int) Math.Ceiling(powerCell.GetComponent<PowerCellComponent>().Capacity / _baseFireCost);
|
return (int) Math.Ceiling((float) (powerCell.GetComponent<BatteryComponent>().MaxCharge / _baseFireCost));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,8 +144,8 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var capacitor = powerCellEntity.GetComponent<PowerCellComponent>();
|
var capacitor = powerCellEntity.GetComponent<BatteryComponent>();
|
||||||
if (capacitor.Charge < _lowerChargeLimit)
|
if (capacitor.CurrentCharge < _lowerChargeLimit)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -153,8 +153,8 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
|||||||
// Can fire confirmed
|
// Can fire confirmed
|
||||||
// Multiply the entity's damage / whatever by the percentage of charge the shot has.
|
// Multiply the entity's damage / whatever by the percentage of charge the shot has.
|
||||||
IEntity entity;
|
IEntity entity;
|
||||||
var chargeChange = Math.Min(capacitor.Charge, _baseFireCost);
|
var chargeChange = Math.Min(capacitor.CurrentCharge, _baseFireCost);
|
||||||
capacitor.DeductCharge(chargeChange);
|
capacitor.UseCharge(chargeChange);
|
||||||
var energyRatio = chargeChange / _baseFireCost;
|
var energyRatio = chargeChange / _baseFireCost;
|
||||||
|
|
||||||
if (_ammoContainer.ContainedEntity != null)
|
if (_ammoContainer.ContainedEntity != null)
|
||||||
@@ -201,7 +201,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!entity.HasComponent<PowerCellComponent>())
|
if (!entity.HasComponent<BatteryComponent>())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -264,7 +264,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels
|
|||||||
|
|
||||||
public override bool InteractUsing(InteractUsingEventArgs eventArgs)
|
public override bool InteractUsing(InteractUsingEventArgs eventArgs)
|
||||||
{
|
{
|
||||||
if (!eventArgs.Using.HasComponent<PowerStorageComponent>())
|
if (!eventArgs.Using.HasComponent<BatteryComponent>())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Content.Server.GameObjects.Components.Power.Chargers;
|
using Content.Server.GameObjects.Components.Power.Chargers;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameObjects.Systems;
|
using Robust.Shared.GameObjects.Systems;
|
||||||
@@ -6,19 +6,18 @@ using Robust.Shared.GameObjects.Systems;
|
|||||||
namespace Content.Server.GameObjects.EntitySystems
|
namespace Content.Server.GameObjects.EntitySystems
|
||||||
{
|
{
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
internal class CellChargerSystem : EntitySystem
|
internal class BaseChargerSystem : EntitySystem
|
||||||
{
|
{
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
EntityQuery = new TypeEntityQuery(typeof(PowerCellChargerComponent));
|
EntityQuery = new TypeEntityQuery(typeof(BaseCharger));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
{
|
{
|
||||||
foreach (var entity in RelevantEntities)
|
foreach (var entity in RelevantEntities)
|
||||||
{
|
{
|
||||||
var comp = entity.GetComponent<PowerCellChargerComponent>();
|
entity.GetComponent<BaseCharger>().OnUpdate(frameTime);
|
||||||
comp.OnUpdate(frameTime);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using Content.Server.GameObjects.Components.Power.PowerNetComponents;
|
||||||
|
using Robust.Server.Interfaces.Timing;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects.Systems;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.EntitySystems
|
||||||
|
{
|
||||||
|
internal class BatteryDischargerSystem : EntitySystem
|
||||||
|
{
|
||||||
|
#pragma warning disable 649
|
||||||
|
[Dependency] private readonly IPauseManager _pauseManager;
|
||||||
|
#pragma warning restore 649
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
EntityQuery = new TypeEntityQuery(typeof(BatteryDischargerComponent));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
foreach (var entity in RelevantEntities)
|
||||||
|
{
|
||||||
|
if (_pauseManager.IsEntityPaused(entity))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
entity.GetComponent<BatteryDischargerComponent>().Update(frameTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using Content.Server.GameObjects.Components.Power.PowerNetComponents;
|
||||||
|
using Robust.Server.Interfaces.Timing;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects.Systems;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.EntitySystems
|
||||||
|
{
|
||||||
|
internal class BatteryStorageSystem : EntitySystem
|
||||||
|
{
|
||||||
|
#pragma warning disable 649
|
||||||
|
[Dependency] private readonly IPauseManager _pauseManager;
|
||||||
|
#pragma warning restore 649
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
EntityQuery = new TypeEntityQuery(typeof(BatteryStorageComponent));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
foreach (var entity in RelevantEntities)
|
||||||
|
{
|
||||||
|
if (_pauseManager.IsEntityPaused(entity))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
entity.GetComponent<BatteryStorageComponent>().Update(frameTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,19 @@
|
|||||||
using Content.Server.GameObjects.Components.Power;
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameObjects.Systems;
|
using Robust.Shared.GameObjects.Systems;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Server.Interfaces.Timing;
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.EntitySystems
|
namespace Content.Server.GameObjects.EntitySystems
|
||||||
{
|
{
|
||||||
class PowerApcSystem : EntitySystem
|
public sealed class ApcSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
#pragma warning disable 649
|
||||||
|
[Dependency] private readonly IPauseManager _pauseManager;
|
||||||
|
#pragma warning restore 649
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
EntityQuery = new TypeEntityQuery(typeof(ApcComponent));
|
EntityQuery = new TypeEntityQuery(typeof(ApcComponent));
|
||||||
@@ -13,10 +21,20 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
|
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
{
|
{
|
||||||
|
var uniqueApcNets = new HashSet<IApcNet>(); //could be improved by maintaining set instead of getting collection every frame
|
||||||
foreach (var entity in RelevantEntities)
|
foreach (var entity in RelevantEntities)
|
||||||
{
|
{
|
||||||
var comp = entity.GetComponent<ApcComponent>();
|
if (_pauseManager.IsEntityPaused(entity))
|
||||||
comp.OnUpdate();
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var apc = entity.GetComponent<ApcComponent>();
|
||||||
|
uniqueApcNets.Add(apc.Net);
|
||||||
|
entity.GetComponent<ApcComponent>().Update();
|
||||||
|
}
|
||||||
|
foreach (var apcNet in uniqueApcNets)
|
||||||
|
{
|
||||||
|
apcNet.Update(frameTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
{
|
{
|
||||||
foreach (var entity in RelevantEntities)
|
foreach (var entity in RelevantEntities)
|
||||||
{
|
{
|
||||||
var comp = entity.GetComponent<SmesComponent>();
|
entity.GetComponent<SmesComponent>().OnUpdate();
|
||||||
comp.OnUpdate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using Content.Server.GameObjects.Components.Power;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.GameObjects.Systems;
|
|
||||||
using Robust.Shared.Interfaces.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
|
|
||||||
namespace Content.Shared.GameObjects.EntitySystems
|
|
||||||
{
|
|
||||||
public class PowerSystem : EntitySystem
|
|
||||||
{
|
|
||||||
public List<Powernet> Powernets = new List<Powernet>();
|
|
||||||
|
|
||||||
private IComponentManager componentManager;
|
|
||||||
|
|
||||||
private int _lastUid = 0;
|
|
||||||
|
|
||||||
public PowerSystem()
|
|
||||||
{
|
|
||||||
EntityQuery = new TypeEntityQuery(typeof(PowerDeviceComponent));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
componentManager = IoCManager.Resolve<IComponentManager>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int NewUid()
|
|
||||||
{
|
|
||||||
return ++_lastUid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update(float frametime)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < Powernets.Count; i++)
|
|
||||||
{
|
|
||||||
var powernet = Powernets[i];
|
|
||||||
if (powernet.Dirty)
|
|
||||||
{
|
|
||||||
//Tell all the wires of this net to be prepared to create/join new powernets
|
|
||||||
foreach (var wire in powernet.WireList)
|
|
||||||
{
|
|
||||||
wire.Regenerating = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var wire in powernet.WireList)
|
|
||||||
{
|
|
||||||
//Only a few wires should pass this if check since each will create and take all the others into its powernet
|
|
||||||
if (wire.Regenerating)
|
|
||||||
wire.SpreadPowernet();
|
|
||||||
}
|
|
||||||
|
|
||||||
//At this point all wires will have found/joined new powernet, all capable nodes will have joined them as well and removed themselves from nodelist
|
|
||||||
powernet.DirtyKill();
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var powernet in Powernets)
|
|
||||||
{
|
|
||||||
powernet.Update(frametime);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw power for devices not connected to anything.
|
|
||||||
foreach (var entity in EntityManager.GetEntities(EntityQuery))
|
|
||||||
{
|
|
||||||
var device = entity.GetComponent<PowerDeviceComponent>();
|
|
||||||
device.ProcessInternalPower(frametime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
using Content.Server.GameObjects.Components.Power;
|
|
||||||
using Content.Server.GameObjects.Components.Power.Chargers;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.GameObjects.Systems;
|
|
||||||
|
|
||||||
namespace Content.Server.GameObjects.EntitySystems
|
|
||||||
{
|
|
||||||
[UsedImplicitly]
|
|
||||||
internal class WeaponCapacitorChargerSystem : EntitySystem
|
|
||||||
{
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
EntityQuery = new TypeEntityQuery(typeof(WeaponCapacitorChargerComponent));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
|
||||||
{
|
|
||||||
foreach (var entity in RelevantEntities)
|
|
||||||
{
|
|
||||||
var comp = entity.GetComponent<WeaponCapacitorChargerComponent>();
|
|
||||||
comp.OnUpdate(frameTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,6 +13,8 @@ using Content.Server.Utility;
|
|||||||
using Content.Shared.Interfaces;
|
using Content.Shared.Interfaces;
|
||||||
using Content.Shared.Kitchen;
|
using Content.Shared.Kitchen;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
|
using Content.Server.GameObjects.Components.NodeContainer.Nodes;
|
||||||
|
|
||||||
namespace Content.Server
|
namespace Content.Server
|
||||||
{
|
{
|
||||||
@@ -31,6 +33,8 @@ namespace Content.Server
|
|||||||
IoCManager.Register<IServerPreferencesManager, ServerPreferencesManager>();
|
IoCManager.Register<IServerPreferencesManager, ServerPreferencesManager>();
|
||||||
IoCManager.Register<RecipeManager, RecipeManager>();
|
IoCManager.Register<RecipeManager, RecipeManager>();
|
||||||
IoCManager.Register<IPDAUplinkManager,PDAUplinkManager>();
|
IoCManager.Register<IPDAUplinkManager,PDAUplinkManager>();
|
||||||
|
IoCManager.Register<INodeGroupFactory, NodeGroupFactory>();
|
||||||
|
IoCManager.Register<INodeFactory, NodeFactory>();
|
||||||
IoCManager.Register<BlackboardManager, BlackboardManager>();
|
IoCManager.Register<BlackboardManager, BlackboardManager>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
namespace Content.Shared.GameObjects.Components.Power
|
namespace Content.Shared.GameObjects.Components.Power
|
||||||
{
|
{
|
||||||
public abstract class SharedApcComponent : Component
|
|
||||||
{
|
|
||||||
public sealed override string Name => "Apc";
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public enum ApcVisuals
|
public enum ApcVisuals
|
||||||
{
|
{
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Serialization;
|
|
||||||
|
|
||||||
namespace Content.Shared.GameObjects.Components.Power
|
|
||||||
{
|
|
||||||
public class SharedPowerDebugTool : Component
|
|
||||||
{
|
|
||||||
public override string Name => "PowerDebugTool";
|
|
||||||
public override uint? NetID => ContentNetIDs.POWER_DEBUG_TOOL;
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
protected class OpenDataWindowMsg : ComponentMessage
|
|
||||||
{
|
|
||||||
public string Data { get; }
|
|
||||||
|
|
||||||
public OpenDataWindowMsg(string data)
|
|
||||||
{
|
|
||||||
Directed = true;
|
|
||||||
Data = data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,11 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: Arcade
|
id: Arcade
|
||||||
name: arcade
|
name: arcade
|
||||||
parent: ComputerBase
|
parent: ComputerBase
|
||||||
components:
|
components:
|
||||||
- type: Icon
|
- type: Icon
|
||||||
state: arcade
|
state: arcade
|
||||||
- type: PowerDevice
|
- type: PowerReceiver
|
||||||
priority: Low
|
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
layers:
|
layers:
|
||||||
- state: arcade
|
- state: arcade
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: Airlock
|
id: Airlock
|
||||||
name: airlock
|
name: airlock
|
||||||
description: It opens, it closes, and maybe crushes you.
|
description: It opens, it closes, and maybe crushes you.
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
close_sound: /Audio/machines/airlock_close.ogg
|
close_sound: /Audio/machines/airlock_close.ogg
|
||||||
deny_sound: /Audio/machines/airlock_deny.ogg
|
deny_sound: /Audio/machines/airlock_deny.ogg
|
||||||
- type: WiresVisualizer2D
|
- type: WiresVisualizer2D
|
||||||
- type: PowerDevice
|
- type: PowerReceiver
|
||||||
- type: Wires
|
- type: Wires
|
||||||
BoardName: "Airlock Control"
|
BoardName: "Airlock Control"
|
||||||
LayoutId: Airlock
|
LayoutId: Airlock
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: BarSign
|
id: BarSign
|
||||||
name: bar sign
|
name: bar sign
|
||||||
components:
|
components:
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
- type: Icon
|
- type: Icon
|
||||||
sprite: Buildings/barsign.rsi
|
sprite: Buildings/barsign.rsi
|
||||||
state: empty
|
state: empty
|
||||||
- type: PowerDevice
|
- type: PowerReceiver
|
||||||
- type: BarSign
|
- type: BarSign
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
texture: Buildings/chemicals.rsi/industrial_dispenser.png
|
texture: Buildings/chemicals.rsi/industrial_dispenser.png
|
||||||
- type: ReagentDispenser
|
- type: ReagentDispenser
|
||||||
pack: ChemDispenserStandardInventory
|
pack: ChemDispenserStandardInventory
|
||||||
- type: PowerDevice
|
- type: PowerReceiver
|
||||||
|
|
||||||
- type: reagentDispenserInventory
|
- type: reagentDispenserInventory
|
||||||
id: ChemDispenserStandardInventory
|
id: ChemDispenserStandardInventory
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: ComputerBase
|
id: ComputerBase
|
||||||
name: computer
|
name: computer
|
||||||
abstract: true
|
abstract: true
|
||||||
@@ -26,8 +26,7 @@
|
|||||||
sprite: Buildings/computer.rsi
|
sprite: Buildings/computer.rsi
|
||||||
state: computer
|
state: computer
|
||||||
- type: Computer
|
- type: Computer
|
||||||
- type: PowerDevice
|
- type: PowerReceiver
|
||||||
priority: High
|
|
||||||
- type: Anchorable
|
- type: Anchorable
|
||||||
|
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
@@ -151,8 +150,7 @@
|
|||||||
type: ResearchConsoleBoundUserInterface
|
type: ResearchConsoleBoundUserInterface
|
||||||
- key: enum.ResearchClientUiKey.Key
|
- key: enum.ResearchClientUiKey.Key
|
||||||
type: ResearchClientBoundUserInterface
|
type: ResearchClientBoundUserInterface
|
||||||
- type: PowerDevice
|
- type: PowerReceiver
|
||||||
drawtype: Both
|
|
||||||
load: 200
|
load: 200
|
||||||
priority: Low
|
priority: Low
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: GravityGenerator
|
id: GravityGenerator
|
||||||
name: gravity generator
|
name: gravity generator
|
||||||
description: It's what keeps you to the floor.
|
description: It's what keeps you to the floor.
|
||||||
@@ -15,8 +15,8 @@
|
|||||||
state: on
|
state: on
|
||||||
- type: SnapGrid
|
- type: SnapGrid
|
||||||
offset: Center
|
offset: Center
|
||||||
- type: PowerDevice
|
- type: PowerReceiver
|
||||||
load: 500
|
powerLoad: 500
|
||||||
- type: Collidable
|
- type: Collidable
|
||||||
shapes:
|
shapes:
|
||||||
- !type:PhysShapeAabb
|
- !type:PhysShapeAabb
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
interfaces:
|
interfaces:
|
||||||
- key: enum.LatheUiKey.Key
|
- key: enum.LatheUiKey.Key
|
||||||
type: LatheBoundUserInterface
|
type: LatheBoundUserInterface
|
||||||
- type: PowerDevice
|
- type: PowerReceiver
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: BaseLathe
|
parent: BaseLathe
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: WallLight
|
id: WallLight
|
||||||
name: "unpowered light"
|
name: "unpowered light"
|
||||||
components:
|
components:
|
||||||
@@ -42,10 +42,9 @@
|
|||||||
state: off
|
state: off
|
||||||
- type: PointLight
|
- type: PointLight
|
||||||
enabled: false
|
enabled: false
|
||||||
- type: PowerDevice
|
|
||||||
priority: Low
|
|
||||||
- type: PoweredLight
|
- type: PoweredLight
|
||||||
bulb: Tube
|
bulb: Tube
|
||||||
|
- type: PowerReceiver
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: small light
|
name: small light
|
||||||
@@ -64,8 +63,6 @@
|
|||||||
energy: 1.0
|
energy: 1.0
|
||||||
enabled: false
|
enabled: false
|
||||||
offset: "-0.5, 0"
|
offset: "-0.5, 0"
|
||||||
- type: PowerDevice
|
|
||||||
priority: Low
|
|
||||||
- type: PoweredLight
|
- type: PoweredLight
|
||||||
bulb: Bulb
|
bulb: Bulb
|
||||||
|
- type: PowerReceiver
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
map: ["enum.MedicalScannerVisualLayers.Machine"]
|
map: ["enum.MedicalScannerVisualLayers.Machine"]
|
||||||
- state: scanner_terminal_blue
|
- state: scanner_terminal_blue
|
||||||
map: ["enum.MedicalScannerVisualLayers.Terminal"]
|
map: ["enum.MedicalScannerVisualLayers.Terminal"]
|
||||||
- type: PowerDevice
|
- type: PowerReceiver
|
||||||
- type: Icon
|
- type: Icon
|
||||||
sprite: Buildings/medical_scanner.rsi
|
sprite: Buildings/medical_scanner.rsi
|
||||||
state: scanner_open
|
state: scanner_open
|
||||||
|
|||||||
@@ -1,49 +1,88 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: Wire
|
abstract: true
|
||||||
name: wire
|
id: WireBase
|
||||||
description: Transfers power, avoid letting things come down it
|
|
||||||
placement:
|
placement:
|
||||||
mode: SnapgridCenter
|
mode: SnapgridCenter
|
||||||
components:
|
components:
|
||||||
- type: Clickable
|
- type: Clickable
|
||||||
- type: InteractionOutline
|
- type: InteractionOutline
|
||||||
- type: Collidable
|
- type: Collidable
|
||||||
- type: Sprite
|
|
||||||
netsync: false
|
|
||||||
drawdepth: BelowFloor
|
|
||||||
color: Red
|
|
||||||
sprite: Objects/Power/power_cable.rsi
|
|
||||||
state: cable_0
|
|
||||||
- type: Icon
|
|
||||||
texture: Objects/Power/eightdirwire.png
|
|
||||||
- type: PowerTransfer
|
|
||||||
- type: SnapGrid
|
- type: SnapGrid
|
||||||
offset: Center
|
offset: Center
|
||||||
|
- type: Icon
|
||||||
|
texture: Objects/Power/eightdirwire.png
|
||||||
|
- type: Sprite
|
||||||
|
drawdepth: BelowFloor
|
||||||
- type: IconSmooth
|
- type: IconSmooth
|
||||||
base: cable_
|
|
||||||
key: power_cables
|
|
||||||
mode: CardinalFlags
|
mode: CardinalFlags
|
||||||
- type: SubFloorHide
|
|
||||||
- type: Destructible
|
- type: Destructible
|
||||||
thresholdvalue: 100
|
thresholdvalue: 100
|
||||||
spawnondestroy: CableStack1
|
- type: SubFloorHide
|
||||||
|
|
||||||
snap:
|
|
||||||
- Wire
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: Wire
|
parent: WireBase
|
||||||
id: BlueWire
|
id: HVWire
|
||||||
name: bluewire
|
name: HV Wire
|
||||||
description: Transfers power, and puts on a good show of it
|
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
color: Blue
|
sprite: Objects/Power/hv_cable.rsi
|
||||||
|
state: hvcable_0
|
||||||
|
- type: IconSmooth
|
||||||
|
base: hvcable_
|
||||||
|
key: hv_cables
|
||||||
|
- type: NodeContainer
|
||||||
|
nodeTypes: { HVPower : ["AdjacentNode"] }
|
||||||
|
- type: Wire
|
||||||
|
wireDroppedOnCutPrototype: HVWireStack1
|
||||||
|
wireType: HighVoltage
|
||||||
|
- type: Destructible
|
||||||
|
spawnondestroy: HVWireStack1
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: Generator
|
parent: WireBase
|
||||||
name: generator
|
id: MVWire
|
||||||
description: A portal to hell which summons power from the nether
|
name: MV Wire
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
color: Yellow
|
||||||
|
sprite: Objects/Power/mv_cable.rsi
|
||||||
|
state: mvcable_0
|
||||||
|
- type: IconSmooth
|
||||||
|
base: mvcable_
|
||||||
|
key: mv_cables
|
||||||
|
- type: NodeContainer
|
||||||
|
nodeTypes: { MVPower : ["AdjacentNode"] }
|
||||||
|
- type: Wire
|
||||||
|
wireDroppedOnCutPrototype: MVWireStack1
|
||||||
|
wireType: MediumVoltage
|
||||||
|
- type: Destructible
|
||||||
|
spawnondestroy: MVWireStack1
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: WireBase
|
||||||
|
id: ApcExtensionCable
|
||||||
|
name: Apc Extension Cable
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
color: Green
|
||||||
|
sprite: Objects/Power/lv_cable.rsi
|
||||||
|
state: lvcable_0
|
||||||
|
- type: IconSmooth
|
||||||
|
base: lvcable_
|
||||||
|
key: lv_cables
|
||||||
|
- type: NodeContainer
|
||||||
|
nodeTypes: { Apc : ["AdjacentNode"] }
|
||||||
|
- type: PowerProvider
|
||||||
|
voltage: Apc
|
||||||
|
- type: Wire
|
||||||
|
wireDroppedOnCutPrototype: ApcExtensionCableStack1
|
||||||
|
wireType: Apc
|
||||||
|
- type: Destructible
|
||||||
|
spawnondestroy: ApcExtensionCableStack1
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: DebugGenerator
|
||||||
|
name: Debug Generator
|
||||||
placement:
|
placement:
|
||||||
mode: SnapgridCenter
|
mode: SnapgridCenter
|
||||||
components:
|
components:
|
||||||
@@ -54,15 +93,215 @@
|
|||||||
- !type:PhysShapeAabb
|
- !type:PhysShapeAabb
|
||||||
bounds: "-0.5, -0.5, 0.3, 0.5"
|
bounds: "-0.5, -0.5, 0.3, 0.5"
|
||||||
layer: [MobMask, Opaque]
|
layer: [MobMask, Opaque]
|
||||||
|
- type: SnapGrid
|
||||||
|
offset: Center
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
texture: Objects/Power/generator.png
|
texture: Objects/Power/generator.png
|
||||||
- type: Icon
|
- type: Icon
|
||||||
texture: Objects/Power/generator.png
|
texture: Objects/Power/generator.png
|
||||||
- type: PowerGenerator
|
- type: NodeContainer
|
||||||
|
nodeTypes: { HVPower : ["AdjacentNode"] }
|
||||||
|
- type: PowerSupplier
|
||||||
|
supplyRate: 3000
|
||||||
|
- type: Anchorable
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: DebugConsumer
|
||||||
|
name: Debug Consumer
|
||||||
|
placement:
|
||||||
|
mode: SnapgridCenter
|
||||||
|
components:
|
||||||
|
- type: Clickable
|
||||||
|
- type: InteractionOutline
|
||||||
|
- type: Collidable
|
||||||
- type: SnapGrid
|
- type: SnapGrid
|
||||||
offset: Center
|
offset: Center
|
||||||
|
- type: Sprite
|
||||||
|
texture: Objects/Power/wiredmachine.png
|
||||||
|
- type: Icon
|
||||||
|
texture: Objects/Power/wiredmachine.png
|
||||||
|
- type: NodeContainer
|
||||||
|
nodeTypes: { HVPower : ["AdjacentNode"] }
|
||||||
|
- type: PowerConsumer
|
||||||
|
drawRate: 50
|
||||||
|
- type: Damageable
|
||||||
|
- type: Breakable
|
||||||
|
thresholdvalue: 100
|
||||||
- type: Anchorable
|
- type: Anchorable
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: DebugBatteryStorage
|
||||||
|
name: Debug Battery Storage
|
||||||
|
placement:
|
||||||
|
mode: SnapgridCenter
|
||||||
|
components:
|
||||||
|
- type: Clickable
|
||||||
|
- type: InteractionOutline
|
||||||
|
- type: Collidable
|
||||||
|
- type: SnapGrid
|
||||||
|
offset: Center
|
||||||
|
- type: Sprite
|
||||||
|
texture: Objects/Power/provider.png
|
||||||
|
- type: Icon
|
||||||
|
texture: Objects/Power/provider.png
|
||||||
|
- type: Battery
|
||||||
|
- type: NodeContainer
|
||||||
|
nodeTypes: { HVPower : ["AdjacentNode"] }
|
||||||
|
- type: PowerConsumer
|
||||||
|
- type: BatteryStorage
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: DebugBatteryDischarger
|
||||||
|
name: Debug Battery Discharger
|
||||||
|
placement:
|
||||||
|
mode: SnapgridCenter
|
||||||
|
components:
|
||||||
|
- type: Clickable
|
||||||
|
- type: InteractionOutline
|
||||||
|
- type: Collidable
|
||||||
|
- type: SnapGrid
|
||||||
|
offset: Center
|
||||||
|
- type: Sprite
|
||||||
|
texture: Objects/Power/provider.png
|
||||||
|
- type: Icon
|
||||||
|
texture: Objects/Power/provider.png
|
||||||
|
- type: Battery
|
||||||
|
- type: NodeContainer
|
||||||
|
nodeTypes: { HVPower : ["AdjacentNode"] }
|
||||||
|
- type: PowerSupplier
|
||||||
|
- type: BatteryDischarger
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: DebugSmes
|
||||||
|
name: Debug Smes
|
||||||
|
placement:
|
||||||
|
mode: SnapgridCenter
|
||||||
|
components:
|
||||||
|
- type: Clickable
|
||||||
|
- type: InteractionOutline
|
||||||
|
- type: Collidable
|
||||||
|
shapes:
|
||||||
|
- !type:PhysShapeAabb
|
||||||
|
bounds: "-0.5, -0.5, 0.5, 0.5"
|
||||||
|
layer: [MobMask, Opaque]
|
||||||
|
- type: SnapGrid
|
||||||
|
offset: Center
|
||||||
|
- type: Sprite
|
||||||
|
netsync: false
|
||||||
|
sprite: Buildings/smes.rsi
|
||||||
|
state: smes
|
||||||
|
layers:
|
||||||
|
- state: smes-display
|
||||||
|
shader: unshaded
|
||||||
|
- type: Icon
|
||||||
|
sprite: Buildings/smes.rsi
|
||||||
|
state: smes
|
||||||
|
- type: Smes
|
||||||
|
- type: Appearance
|
||||||
|
visuals:
|
||||||
|
- type: SmesVisualizer2D
|
||||||
|
- type: Battery
|
||||||
|
maxCharge: 1000
|
||||||
|
startingCharge: 1000
|
||||||
|
- type: NodeContainer
|
||||||
|
nodeTypes: { HVPower : ["AdjacentNode"] }
|
||||||
|
- type: PowerConsumer
|
||||||
|
- type: BatteryStorage
|
||||||
|
activeDrawRate: 1500
|
||||||
|
- type: PowerSupplier
|
||||||
|
- type: BatteryDischarger
|
||||||
|
activeSupplyRate: 1000
|
||||||
|
- type: Anchorable
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: DebugSubstation
|
||||||
|
name: Debug Substation
|
||||||
|
placement:
|
||||||
|
mode: SnapgridCenter
|
||||||
|
components:
|
||||||
|
- type: Clickable
|
||||||
|
- type: InteractionOutline
|
||||||
|
- type: Collidable
|
||||||
|
- type: SnapGrid
|
||||||
|
offset: Center
|
||||||
|
- type: Sprite
|
||||||
|
texture: Objects\Power\storage.png
|
||||||
|
- type: Icon
|
||||||
|
texture: Objects\Power\storage.png
|
||||||
|
state: smes
|
||||||
|
- type: Battery
|
||||||
|
maxCharge: 1000
|
||||||
|
startingCharge: 1000
|
||||||
|
- type: NodeContainer
|
||||||
|
nodeTypes: { HVPower : ["AdjacentNode"], MVPower : ["AdjacentNode"] }
|
||||||
|
- type: PowerConsumer
|
||||||
|
- type: BatteryStorage
|
||||||
|
activeDrawRate: 1500
|
||||||
|
- type: PowerSupplier
|
||||||
|
voltage: Medium
|
||||||
|
- type: BatteryDischarger
|
||||||
|
activeSupplyRate: 1000
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: DebugApc
|
||||||
|
name: Debug Apc
|
||||||
|
placement:
|
||||||
|
mode: SnapgridCenter
|
||||||
|
components:
|
||||||
|
- type: Clickable
|
||||||
|
- type: InteractionOutline
|
||||||
|
- type: Collidable
|
||||||
|
shapes:
|
||||||
|
- !type:PhysShapeAabb
|
||||||
|
bounds: "-0.25, -0.25, 0.25, 0.3"
|
||||||
|
- type: SnapGrid
|
||||||
|
offset: Center
|
||||||
|
- type: Sprite
|
||||||
|
drawdepth: WallMountedItems
|
||||||
|
netsync: false
|
||||||
|
texture: ""
|
||||||
|
sprite: "Buildings/apc.rsi"
|
||||||
|
state: apc0
|
||||||
|
- type: Icon
|
||||||
|
texture: Buildings/apc.rsi/apc0.png
|
||||||
|
- type: Appearance
|
||||||
|
visuals:
|
||||||
|
- type: ApcVisualizer2D
|
||||||
|
- type: Battery
|
||||||
|
maxCharge: 10000
|
||||||
|
startingCharge: 10000
|
||||||
|
- type: NodeContainer
|
||||||
|
nodeTypes: { MVPower : ["AdjacentNode"], Apc : ["AdjacentNode"] }
|
||||||
|
- type: PowerConsumer
|
||||||
|
voltage: Medium
|
||||||
|
- type: BatteryStorage
|
||||||
|
activeDrawRate: 1000
|
||||||
|
- type: PowerProvider
|
||||||
|
voltage: Apc
|
||||||
|
- type: Apc
|
||||||
|
voltage: Apc
|
||||||
|
- type: UserInterface
|
||||||
|
interfaces:
|
||||||
|
- key: enum.ApcUiKey.Key
|
||||||
|
type: ApcBoundUserInterface
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: DebugPowerReceiver
|
||||||
|
name: Debug Power Receiver
|
||||||
|
placement:
|
||||||
|
mode: SnapgridCenter
|
||||||
|
components:
|
||||||
|
- type: Clickable
|
||||||
|
- type: InteractionOutline
|
||||||
|
- type: Collidable
|
||||||
|
- type: SnapGrid
|
||||||
|
offset: Center
|
||||||
|
- type: Sprite
|
||||||
|
texture: Objects/Furniture/wirelessmachine.png
|
||||||
|
- type: Icon
|
||||||
|
texture: Objects/Furniture/wirelessmachine.png
|
||||||
|
- type: PowerReceiver
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: SolarPanel
|
id: SolarPanel
|
||||||
name: solar panel
|
name: solar panel
|
||||||
@@ -82,7 +321,9 @@
|
|||||||
- type: Icon
|
- type: Icon
|
||||||
sprite: Buildings/solar_panel.rsi
|
sprite: Buildings/solar_panel.rsi
|
||||||
state: normal
|
state: normal
|
||||||
- type: PowerGenerator
|
- type: NodeContainer
|
||||||
|
nodeTypes: { HVPower : ["AdjacentNode"] }
|
||||||
|
- type: PowerSupplier
|
||||||
- type: SolarPanel
|
- type: SolarPanel
|
||||||
supply: 1500
|
supply: 1500
|
||||||
- type: SnapGrid
|
- type: SnapGrid
|
||||||
@@ -90,160 +331,54 @@
|
|||||||
- type: Damageable
|
- type: Damageable
|
||||||
- type: Breakable
|
- type: Breakable
|
||||||
thresholdvalue: 100
|
thresholdvalue: 100
|
||||||
- type: Anchorable
|
|
||||||
|
#Depriciated, to be removed from maps
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: WPPnobattery
|
id: Wire
|
||||||
name: wppnobattery
|
name: Depriciated Wire
|
||||||
description: Supplies power directly to nearby objects
|
parent: ApcExtensionCable
|
||||||
placement:
|
|
||||||
mode: SnapgridCenter
|
|
||||||
components:
|
components:
|
||||||
- type: Clickable
|
- type: NodeContainer
|
||||||
- type: InteractionOutline
|
nodeTypes: { HVPower : ["AdjacentNode"], Apc : ["AdjacentNode"] }
|
||||||
- type: Collidable
|
|
||||||
shapes:
|
|
||||||
- !type:PhysShapeAabb
|
|
||||||
layer: [Clickable]
|
|
||||||
- type: Sprite
|
|
||||||
drawdepth: WallMountedItems
|
|
||||||
texture: Objects/Power/provider.png
|
|
||||||
- type: Icon
|
|
||||||
texture: Objects/Power/provider.png
|
|
||||||
- type: PowerProvider
|
|
||||||
range: 8
|
|
||||||
priority: Provider
|
|
||||||
load: 0
|
|
||||||
- type: SnapGrid
|
|
||||||
offset: Center
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: WPPnobattery
|
id: Generator
|
||||||
id: WPP
|
name: Depriciated Generator
|
||||||
name: WPP
|
parent: DebugGenerator
|
||||||
description: Supplies power at range, has a backup battery just in case
|
|
||||||
components:
|
components:
|
||||||
- type: PowerStorage
|
- type: PowerSupplier
|
||||||
capacity: 1000
|
voltage: High
|
||||||
charge: 1000
|
supplyRate: 100000
|
||||||
chargerate: 200
|
|
||||||
chargepowernet: false
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: WPP
|
|
||||||
id: APC
|
id: APC
|
||||||
name: APC
|
name: Depriciated Apc
|
||||||
|
parent: DebugApc
|
||||||
components:
|
components:
|
||||||
- type: Apc
|
- type: NodeContainer
|
||||||
- type: Sprite
|
nodeTypes: { HVPower : ["AdjacentNode"], Apc : ["AdjacentNode"] }
|
||||||
netsync: false
|
- type: PowerConsumer
|
||||||
texture: ""
|
voltage: High
|
||||||
sprite: "Buildings/apc.rsi"
|
- type: BatteryStorage
|
||||||
state: apc0
|
activeDrawRate: 10000
|
||||||
- type: Appearance
|
|
||||||
visuals:
|
|
||||||
- type: ApcVisualizer2D
|
|
||||||
- type: UserInterface
|
|
||||||
interfaces:
|
|
||||||
- key: enum.ApcUiKey.Key
|
|
||||||
type: ApcBoundUserInterface
|
|
||||||
- type: Collidable
|
|
||||||
shapes:
|
|
||||||
- !type:PhysShapeAabb
|
|
||||||
bounds: "-0.25, -0.25, 0.25, 0.3"
|
|
||||||
- type: LoopingSound
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: SMES
|
id: SMES
|
||||||
name: smes
|
name: Depriciated Smes
|
||||||
description: Stores power in its super-magnetic cells
|
parent: DebugSmes
|
||||||
placement:
|
|
||||||
mode: SnapgridCenter
|
|
||||||
components:
|
|
||||||
- type: Clickable
|
|
||||||
- type: InteractionOutline
|
|
||||||
- type: Collidable
|
|
||||||
shapes:
|
|
||||||
- !type:PhysShapeAabb
|
|
||||||
bounds: "-0.5, -0.5, 0.5, 0.5"
|
|
||||||
layer: [MobMask, Opaque]
|
|
||||||
- type: Sprite
|
|
||||||
netsync: false
|
|
||||||
sprite: Buildings/smes.rsi
|
|
||||||
state: smes
|
|
||||||
layers:
|
|
||||||
- state: smes-display
|
|
||||||
shader: unshaded
|
|
||||||
- type: Icon
|
|
||||||
sprite: Buildings/smes.rsi
|
|
||||||
state: smes
|
|
||||||
- type: PowerStorage
|
|
||||||
capacity: 3000
|
|
||||||
charge: 1000
|
|
||||||
chargerate: 200
|
|
||||||
distributionrate: 400
|
|
||||||
chargepowernet: true
|
|
||||||
- type: Smes
|
|
||||||
- type: Appearance
|
|
||||||
visuals:
|
|
||||||
- type: SmesVisualizer2D
|
|
||||||
- type: SnapGrid
|
|
||||||
offset: Center
|
|
||||||
- type: Anchorable
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: SmesDry
|
id: SmesDry
|
||||||
parent: SMES
|
name: Depriciated Smes
|
||||||
components:
|
parent: DebugSmes
|
||||||
- type: PowerStorage
|
|
||||||
charge: 0
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: WiredMachine
|
id: WiredMachine
|
||||||
name: wiredmachine
|
name: Depriciated WiredMachine
|
||||||
description: A monstrosity that does nothing but suck up power from the nearby wires
|
parent: DebugConsumer
|
||||||
placement:
|
|
||||||
mode: SnapgridCenter
|
|
||||||
components:
|
|
||||||
- type: Clickable
|
|
||||||
- type: InteractionOutline
|
|
||||||
- type: Collidable
|
|
||||||
shapes:
|
|
||||||
- !type:PhysShapeAabb
|
|
||||||
bounds: "-0.5, -0.25, 0.5, 0.25"
|
|
||||||
layer: [MobMask, Opaque]
|
|
||||||
- type: Sprite
|
|
||||||
texture: Objects/Power/wiredmachine.png
|
|
||||||
- type: Icon
|
|
||||||
texture: Objects/Power/wiredmachine.png
|
|
||||||
- type: PowerDevice
|
|
||||||
drawtype: Node
|
|
||||||
load: 100
|
|
||||||
priority: High
|
|
||||||
- type: SnapGrid
|
|
||||||
offset: Center
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: WirelessMachine
|
id: WirelessMachine
|
||||||
name: wirelessmachine
|
name: Depriciated WirelessMachine
|
||||||
description: A terrifying monstrosity that sucks up power from the wireless transmitters, Tesla would be proud
|
parent: DebugPowerReceiver
|
||||||
placement:
|
|
||||||
mode: SnapgridCenter
|
|
||||||
components:
|
|
||||||
- type: Clickable
|
|
||||||
- type: InteractionOutline
|
|
||||||
- type: Collidable
|
|
||||||
shapes:
|
|
||||||
- !type:PhysShapeAabb
|
|
||||||
bounds: "-0.5, -0.25, 0.5, 0.25"
|
|
||||||
layer: [MobMask, Opaque]
|
|
||||||
- type: Sprite
|
|
||||||
texture: Objects/Furniture/wirelessmachine.png
|
|
||||||
- type: Icon
|
|
||||||
texture: Objects/Furniture/wirelessmachine.png
|
|
||||||
- type: PowerDevice
|
|
||||||
drawtype: Both
|
|
||||||
load: 200
|
|
||||||
priority: Low
|
|
||||||
- type: SnapGrid
|
|
||||||
offset: Center
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
- type: SnapGrid
|
- type: SnapGrid
|
||||||
offset: Center
|
offset: Center
|
||||||
- type: ReagentDispenser
|
- type: ReagentDispenser
|
||||||
- type: PowerDevice
|
- type: PowerReceiver
|
||||||
- type: UserInterface
|
- type: UserInterface
|
||||||
interfaces:
|
interfaces:
|
||||||
- key: enum.ReagentDispenserUiKey.Key
|
- key: enum.ReagentDispenserUiKey.Key
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: VendingMachine
|
id: VendingMachine
|
||||||
name: vending machine
|
name: vending machine
|
||||||
components:
|
components:
|
||||||
@@ -45,8 +45,7 @@
|
|||||||
type: VendingMachineBoundUserInterface
|
type: VendingMachineBoundUserInterface
|
||||||
- key: enum.WiresUiKey.Key
|
- key: enum.WiresUiKey.Key
|
||||||
type: WiresBoundUserInterface
|
type: WiresBoundUserInterface
|
||||||
- type: PowerDevice
|
- type: PowerReceiver
|
||||||
priority: Low
|
|
||||||
- type: Wires
|
- type: Wires
|
||||||
BoardName: "Vending Machine"
|
BoardName: "Vending Machine"
|
||||||
LayoutId: Vending
|
LayoutId: Vending
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
name: material stack
|
name: material stack
|
||||||
id: MaterialStack
|
id: MaterialStack
|
||||||
abstract: true
|
abstract: true
|
||||||
@@ -67,15 +67,14 @@
|
|||||||
count: 1
|
count: 1
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: cable coil
|
|
||||||
id: CableStack
|
id: CableStack
|
||||||
|
abstract: true
|
||||||
parent: BaseItem
|
parent: BaseItem
|
||||||
components:
|
components:
|
||||||
- type: Stack
|
- type: Stack
|
||||||
stacktype: enum.StackType.Cable
|
stacktype: enum.StackType.Cable
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
texture: Objects/Tools/cable_coil.png
|
texture: Objects/Tools/cable_coil.png
|
||||||
color: red
|
|
||||||
- type: Icon
|
- type: Icon
|
||||||
texture: Objects/Tools/cable_coil.png
|
texture: Objects/Tools/cable_coil.png
|
||||||
- type: WirePlacer
|
- type: WirePlacer
|
||||||
@@ -84,10 +83,59 @@
|
|||||||
all: -0.15,-0.15,0.15,0.15
|
all: -0.15,-0.15,0.15,0.15
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: CableStack1
|
id: HVWireStack
|
||||||
name: cable stack 1
|
name: HV Wire Coil
|
||||||
parent: CableStack
|
parent: CableStack
|
||||||
components:
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
color: Orange
|
||||||
|
- type: WirePlacer
|
||||||
|
wirePrototypeID: HVWire
|
||||||
|
blockingWireType: HighVoltage
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: MVWireStack
|
||||||
|
name: MV Wire Coil
|
||||||
|
parent: CableStack
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
color: Yellow
|
||||||
|
- type: WirePlacer
|
||||||
|
wirePrototypeID: MVWire
|
||||||
|
blockingWireType: MediumVoltage
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ApcExtensionCableStack
|
||||||
|
name: Apc Extension Cable Coil
|
||||||
|
parent: CableStack
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
color: Green
|
||||||
|
- type: WirePlacer
|
||||||
|
wirePrototypeID: ApcExtensionCable
|
||||||
|
blockingWireType: Apc
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: HVWireStack1
|
||||||
|
name: HV Wire stack 1
|
||||||
|
parent: HVWireStack
|
||||||
|
components:
|
||||||
|
- type: Stack
|
||||||
|
count: 1
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: MVWireStack1
|
||||||
|
name: MV Wire stack 1
|
||||||
|
parent: MVWireStack
|
||||||
|
components:
|
||||||
|
- type: Stack
|
||||||
|
count: 1
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ApcExtensionCableStack1
|
||||||
|
name: Apc Extension Cable stack 1
|
||||||
|
parent: ApcExtensionCableStack
|
||||||
|
components:
|
||||||
- type: Stack
|
- type: Stack
|
||||||
count: 1
|
count: 1
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
- type: entity
|
|
||||||
name: power debug tool
|
|
||||||
parent: BaseItem
|
|
||||||
id: PowerDebug
|
|
||||||
description: An advanced tool to copy, store, and send electrical pulses and signals through wires and machines
|
|
||||||
components:
|
|
||||||
- type: Sprite
|
|
||||||
sprite: Objects/Tools/multitool.rsi
|
|
||||||
state: multitool
|
|
||||||
|
|
||||||
- type: Icon
|
|
||||||
sprite: Objects/Tools/multitool.rsi
|
|
||||||
state: multitool
|
|
||||||
|
|
||||||
- type: Item
|
|
||||||
sprite: Objects/Tools/multitool.rsi
|
|
||||||
|
|
||||||
- type: PowerDebugTool
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user