using Content.Shared.GameObjects.Components.Power;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using System;
using Robust.Shared.ViewVariables;
using YamlDotNet.RepresentationModel;
namespace Content.Server.GameObjects.Components.Power
{
///
/// Stores electrical energy. Used by power cells and SMESes.
///
public abstract class PowerStorageComponent : Component
{
[ViewVariables]
public ChargeState LastChargeState { get; private set; } = ChargeState.Still;
public DateTime LastChargeStateChange { get; private set; }
///
/// Maximum amount of energy the internal battery can store.
/// In Joules.
///
[ViewVariables]
public float Capacity => _capacity;
private float _capacity = 10000; // Arbitrary value, replace.
///
/// Energy the battery is currently storing.
/// In Joules.
/// In most cases you should use and to modify this.
///
[ViewVariables(VVAccess.ReadWrite)]
public virtual float Charge
{
get => _charge;
set => _charge = value;
}
private float _charge = 0;
///
/// Rate at which energy will be taken to charge internal battery.
/// In Watts.
///
[ViewVariables]
public float ChargeRate => _chargeRate;
private float _chargeRate = 1000;
///
/// Rate at which energy will be distributed to the powernet if needed.
/// In Watts.
///
[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();
}
}
///
/// Checks if the storage can supply the amount of charge directly requested
///
public bool CanDeductCharge(float toDeduct)
{
if (Charge > toDeduct)
return true;
return false;
}
///
/// Deducts the requested charge from the energy storage
///
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();
}
///
/// Returns the amount of energy that can be taken in by this storage in the specified amount of time.
///
public float RequestCharge(float frameTime)
{
return Math.Min(ChargeRate * frameTime, Capacity - Charge);
}
///
/// Returns the amount of energy available for discharge in the specified amount of time.
///
public float AvailableCharge(float frameTime)
{
return Math.Min(DistributionRate * frameTime, Charge);
}
///
/// Tries to deduct a wattage over a certain amount of time.
///
/// The wattage of the power drain.
/// The amount of time in this "frame".
/// True if the amount of energy was deducted, false.
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));
}
}
}