@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||
using Content.Server.GameObjects.Components.Power;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces.GameTicking;
|
||||
using Content.Shared.GameObjects.Components.Power;
|
||||
using Robust.Server.GameObjects.Components.UserInterface;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Server.Interfaces.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Power
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IActivate))]
|
||||
public class SolarControlConsoleComponent : SharedSolarControlConsoleComponent, IActivate
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[Dependency] private IEntitySystemManager _entitySystemManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
private BoundUserInterface _userInterface;
|
||||
private PowerReceiverComponent _powerReceiver;
|
||||
private PowerSolarSystem _powerSolarSystem;
|
||||
private bool Powered => _powerReceiver.Powered;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(SolarControlConsoleUiKey.Key);
|
||||
_userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
|
||||
_powerReceiver = Owner.GetComponent<PowerReceiverComponent>();
|
||||
_powerSolarSystem = _entitySystemManager.GetEntitySystem<PowerSolarSystem>();
|
||||
}
|
||||
|
||||
public void UpdateUIState()
|
||||
{
|
||||
_userInterface.SetState(new SolarControlConsoleBoundInterfaceState(_powerSolarSystem.TargetPanelRotation, _powerSolarSystem.TargetPanelVelocity, _powerSolarSystem.TotalPanelPower, _powerSolarSystem.TowardsSun));
|
||||
}
|
||||
|
||||
private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage obj)
|
||||
{
|
||||
switch (obj.Message)
|
||||
{
|
||||
case SolarControlConsoleAdjustMessage msg:
|
||||
if (double.IsFinite(msg.Rotation))
|
||||
{
|
||||
_powerSolarSystem.TargetPanelRotation = msg.Rotation.Reduced();
|
||||
}
|
||||
if (double.IsFinite(msg.AngularVelocity))
|
||||
{
|
||||
_powerSolarSystem.TargetPanelVelocity = msg.AngularVelocity.Reduced();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void IActivate.Activate(ActivateEventArgs eventArgs)
|
||||
{
|
||||
if (!eventArgs.User.TryGetComponent(out IActorComponent actor))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Powered)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// always update the UI immediately before opening, just in case
|
||||
UpdateUIState();
|
||||
_userInterface.Open(actor.playerSession);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using Content.Server.GameObjects.Components.Damage;
|
||||
using Content.Server.GameObjects.Components.Power.PowerNetComponents;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.Audio;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Server.GameObjects.EntitySystems;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Interfaces.Random;
|
||||
using Robust.Shared.Interfaces.Timing;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Power
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This is a solar panel.
|
||||
/// It generates power from the sun based on coverage.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class SolarPanelComponent : Component, IBreakAct
|
||||
{
|
||||
public override string Name => "SolarPanel";
|
||||
|
||||
private PowerSupplierComponent _powerSupplier;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum supply output by this panel (coverage = 1)
|
||||
/// </summary>
|
||||
private int _maxSupply = 1500;
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int MaxSupply
|
||||
{
|
||||
get => _maxSupply;
|
||||
set {
|
||||
_maxSupply = value;
|
||||
UpdateSupply();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Current coverage of this panel (from 0 to 1).
|
||||
/// This is updated by <see cref='PowerSolarSystem'/>.
|
||||
/// </summary>
|
||||
private float _coverage = 0;
|
||||
[ViewVariables]
|
||||
public float Coverage
|
||||
{
|
||||
get => _coverage;
|
||||
set {
|
||||
// This gets updated once-per-tick, so avoid updating it if truly unnecessary
|
||||
if (_coverage != value) {
|
||||
_coverage = value;
|
||||
UpdateSupply();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The game time (<see cref='IGameTiming'/>) of the next coverage update.
|
||||
/// This may have a random offset applied.
|
||||
/// This is used to reduce solar panel updates and stagger them to prevent lagspikes.
|
||||
/// This should only be updated by the PowerSolarSystem but is viewable for debugging.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public TimeSpan TimeOfNextCoverageUpdate = TimeSpan.MinValue;
|
||||
|
||||
private void UpdateSupply()
|
||||
{
|
||||
if (_powerSupplier != null)
|
||||
_powerSupplier.SupplyRate = (int) (_maxSupply * _coverage);
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_powerSupplier = Owner.GetComponent<PowerSupplierComponent>();
|
||||
UpdateSupply();
|
||||
}
|
||||
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
|
||||
serializer.DataField(ref _maxSupply, "maxsupply", 1500);
|
||||
}
|
||||
|
||||
public void OnBreak(BreakageEventArgs args)
|
||||
{
|
||||
var sprite = Owner.GetComponent<SpriteComponent>();
|
||||
sprite.LayerSetState(0, "broken");
|
||||
MaxSupply = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user