]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
ECS BatteryComponent (#15337)
authorLeon Friedrich <60421075+ElectroJr@users.noreply.github.com>
Wed, 19 Apr 2023 10:10:08 +0000 (22:10 +1200)
committerGitHub <noreply@github.com>
Wed, 19 Apr 2023 10:10:08 +0000 (20:10 +1000)
Content.Server/Power/Components/BatteryComponent.cs
Content.Server/Power/EntitySystems/ApcSystem.cs
Content.Server/Power/EntitySystems/BatterySystem.cs
Content.Server/PowerCell/PowerCellSystem.cs
Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs
Content.Server/Weapons/Ranged/Systems/GunSystem.cs

index 55202e1e70b991e72503bb096dd921e5e34c3f64..8071321745a73d6b27d44fc0c023c1980192315b 100644 (file)
@@ -1,3 +1,5 @@
+using Content.Server.Power.EntitySystems;
+
 namespace Content.Server.Power.Components
 {
     /// <summary>
@@ -12,17 +14,32 @@ namespace Content.Server.Power.Components
         /// <summary>
         /// Maximum charge of the battery in joules (ie. watt seconds)
         /// </summary>
-        [ViewVariables(VVAccess.ReadWrite)] public float MaxCharge { get => _maxCharge; set => SetMaxCharge(value); }
+        [ViewVariables(VVAccess.ReadWrite)]
+        public float MaxCharge
+        {
+            get => _maxCharge;
+            [Obsolete("Use system method")]
+            set => _entMan.System<BatterySystem>().SetMaxCharge(Owner, value, this);
+        }
+
         [DataField("maxCharge")]
-        private float _maxCharge;
+        [Access(typeof(BatterySystem))]
+        public float _maxCharge;
 
         /// <summary>
         /// Current charge of the battery in joules (ie. watt seconds)
         /// </summary>
         [ViewVariables(VVAccess.ReadWrite)]
-        public float CurrentCharge { get => _currentCharge; set => SetCurrentCharge(value); }
+        public float CurrentCharge
+        {
+            get => Charge;
+            [Obsolete("Use system method")]
+            set => _entMan.System<BatterySystem>().SetCharge(Owner, value, this);
+        }
+
         [DataField("startingCharge")]
-        private float _currentCharge;
+        [Access(typeof(BatterySystem))]
+        public float Charge;
 
         /// <summary>
         /// True if the battery is fully charged.
@@ -36,61 +53,14 @@ namespace Content.Server.Power.Components
         [ViewVariables(VVAccess.ReadWrite)]
         public float PricePerJoule = 0.0001f;
 
-        /// <summary>
-        ///     If sufficient charge is avaiable on the battery, use it. Otherwise, don't.
-        /// </summary>
-        public virtual bool TryUseCharge(float chargeToUse)
-        {
-            if (chargeToUse > CurrentCharge)
-            {
-                return false;
-            }
-            else
-            {
-                CurrentCharge -= chargeToUse;
-                return true;
-            }
-        }
-
-        public virtual 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()
-        {
-            _entMan.EventBus.RaiseLocalEvent(Owner, new ChargeChangedEvent(), false);
-        }
-
-        private void SetMaxCharge(float newMax)
-        {
-            _maxCharge = Math.Max(newMax, 0);
-            _currentCharge = Math.Min(_currentCharge, MaxCharge);
-            OnChargeChanged();
-        }
-
-        private void SetCurrentCharge(float newChargeAmount)
-        {
-            _currentCharge = MathHelper.Clamp(newChargeAmount, 0, MaxCharge);
-            OnChargeChanged();
-        }
+        [Obsolete("Use system method")]
+        public bool TryUseCharge(float value)
+            => _entMan.System<BatterySystem>().TryUseCharge(Owner, value, this);
     }
 
-    public struct ChargeChangedEvent {}
+    /// <summary>
+    ///     Raised when a battery's charge or capacity changes (capacity affects relative charge percentage).
+    /// </summary>
+    [ByRefEvent]
+    public record struct ChargeChangedEvent(float Charge, float MaxCharge);
 }
index a66677970a6732e578d6ac0fb771dfaa9bc80369..496ed0150019eecd10e1d845dea656decfc1d0f3 100644 (file)
@@ -1,6 +1,7 @@
 using Content.Server.Emp;
 using Content.Server.Popups;
 using Content.Server.Power.Components;
+using Content.Server.Power.Pow3r;
 using Content.Shared.Access.Components;
 using Content.Shared.Access.Systems;
 using Content.Shared.APC;
@@ -54,7 +55,7 @@ namespace Content.Server.Power.EntitySystems
         }
 
         // Change the APC's state only when the battery state changes, or when it's first created.
-        private void OnBatteryChargeChanged(EntityUid uid, ApcComponent component, ChargeChangedEvent args)
+        private void OnBatteryChargeChanged(EntityUid uid, ApcComponent component, ref ChargeChangedEvent args)
         {
             UpdateApcState(uid, component);
         }
@@ -116,7 +117,7 @@ namespace Content.Server.Power.EntitySystems
 
         public void UpdateApcState(EntityUid uid,
             ApcComponent? apc=null,
-            BatteryComponent? battery=null)
+            PowerNetworkBatteryComponent? battery = null)
         {
             if (!Resolve(uid, ref apc, ref battery))
                 return;
@@ -126,7 +127,7 @@ namespace Content.Server.Power.EntitySystems
                 UpdatePanelAppearance(uid, appearance, apc);
             }
 
-            var newState = CalcChargeState(uid, apc, battery);
+            var newState = CalcChargeState(uid, battery.NetworkBattery);
             if (newState != apc.LastChargeState && apc.LastChargeStateTime + ApcComponent.VisualsChangeDelay < _gameTiming.CurTime)
             {
                 apc.LastChargeState = newState;
@@ -138,7 +139,7 @@ namespace Content.Server.Power.EntitySystems
                 }
             }
 
-            var extPowerState = CalcExtPowerState(uid, apc, battery);
+            var extPowerState = CalcExtPowerState(uid, battery.NetworkBattery);
             if (extPowerState != apc.LastExternalState
                 || apc.LastUiUpdate + ApcComponent.VisualsChangeDelay < _gameTiming.CurTime)
             {
@@ -150,58 +151,43 @@ namespace Content.Server.Power.EntitySystems
 
         public void UpdateUIState(EntityUid uid,
             ApcComponent? apc = null,
-            BatteryComponent? battery = null,
+            PowerNetworkBatteryComponent? netBat = null,
             ServerUserInterfaceComponent? ui = null)
         {
-            if (!Resolve(uid, ref apc, ref battery, ref ui))
+            if (!Resolve(uid, ref apc, ref netBat, ref ui))
                 return;
 
-            var netBattery = Comp<PowerNetworkBatteryComponent>(uid);
-            float power = netBattery is not null ? netBattery.CurrentSupply : 0f;
+            var battery = netBat.NetworkBattery;
 
-            if (_userInterfaceSystem.GetUiOrNull(uid, ApcUiKey.Key, ui) is { } bui)
-            {
-                bui.SetState(new ApcBoundInterfaceState(apc.MainBreakerEnabled, apc.HasAccess, (int)MathF.Ceiling(power), apc.LastExternalState, battery.CurrentCharge / battery.MaxCharge));
-            }
+            var state = new ApcBoundInterfaceState(apc.MainBreakerEnabled, apc.HasAccess,
+                (int) MathF.Ceiling(battery.CurrentSupply), apc.LastExternalState,
+                battery.AvailableSupply / battery.Capacity);
+
+            _userInterfaceSystem.TrySetUiState(uid, ApcUiKey.Key, state, ui: ui);
         }
 
-        public ApcChargeState CalcChargeState(EntityUid uid,
-            ApcComponent? apc=null,
-            BatteryComponent? battery=null)
+        private ApcChargeState CalcChargeState(EntityUid uid, PowerState.Battery battery)
         {
-            if (apc != null && HasComp<EmaggedComponent>(uid))
+            if (HasComp<EmaggedComponent>(uid))
                 return ApcChargeState.Emag;
 
-            if (!Resolve(uid, ref apc, ref battery))
-                return ApcChargeState.Lack;
-
-            var chargeFraction = battery.CurrentCharge / battery.MaxCharge;
-
-            if (chargeFraction > ApcComponent.HighPowerThreshold)
+            if (battery.CurrentStorage / battery.Capacity > ApcComponent.HighPowerThreshold)
             {
                 return ApcChargeState.Full;
             }
 
-            var netBattery = Comp<PowerNetworkBatteryComponent>(uid);
-            var delta = netBattery.CurrentSupply - netBattery.CurrentReceiving;
-
+            var delta = battery.CurrentSupply - battery.CurrentReceiving;
             return delta < 0 ? ApcChargeState.Charging : ApcChargeState.Lack;
         }
 
-        public ApcExternalPowerState CalcExtPowerState(EntityUid uid,
-            ApcComponent? apc=null,
-            BatteryComponent? battery=null)
+        private ApcExternalPowerState CalcExtPowerState(EntityUid uid, PowerState.Battery battery)
         {
-            if (!Resolve(uid, ref apc, ref battery))
-                return ApcExternalPowerState.None;
-
-            var netBat = Comp<PowerNetworkBatteryComponent>(uid);
-            if (netBat.CurrentReceiving == 0 && !MathHelper.CloseTo(battery.CurrentCharge / battery.MaxCharge, 1))
+            if (battery.CurrentReceiving == 0 && !MathHelper.CloseTo(battery.CurrentStorage / battery.Capacity, 1))
             {
                 return ApcExternalPowerState.None;
             }
 
-            var delta = netBat.CurrentReceiving - netBat.CurrentSupply;
+            var delta = battery.CurrentSupply - battery.CurrentReceiving;
             if (!MathHelper.CloseToPercent(delta, 0, 0.1f) && delta < 0)
             {
                 return ApcExternalPowerState.Low;
index 0d2bfb3c25edf6569b11b015052d4d22c1aa7ff9..479d07c26a3b61fbbc058c8c693688289b9fef98 100644 (file)
@@ -4,6 +4,7 @@ using Content.Server.Power.Components;
 using Content.Shared.Examine;
 using Content.Shared.Rejuvenate;
 using JetBrains.Annotations;
+using Robust.Shared.Utility;
 
 namespace Content.Server.Power.EntitySystems
 {
@@ -61,8 +62,9 @@ namespace Content.Server.Power.EntitySystems
             var enumerator = AllEntityQuery<PowerNetworkBatteryComponent, BatteryComponent>();
             while (enumerator.MoveNext(out var netBat, out var bat))
             {
+                DebugTools.Assert(bat.Charge <= bat.MaxCharge && bat.Charge >= 0);
                 netBat.NetworkBattery.Capacity = bat.MaxCharge;
-                netBat.NetworkBattery.CurrentStorage = bat.CurrentCharge;
+                netBat.NetworkBattery.CurrentStorage = bat.Charge;
             }
         }
 
@@ -73,10 +75,17 @@ namespace Content.Server.Power.EntitySystems
             while (enumerator.MoveNext(out var uid, out var netBat, out var bat))
             {
                 var netCharge = netBat.NetworkBattery.CurrentStorage;
+
+                bat.Charge = netCharge;
+                DebugTools.Assert(bat.Charge <= bat.MaxCharge && bat.Charge >= 0);
+
+                // TODO maybe decrease tolerance & track the charge at the time the event was most recently raised.
+                // Ensures that events aren't skipped when there are many tiny power changes.
                 if (MathHelper.CloseTo(bat.CurrentCharge, netCharge))
                     continue;
 
-                bat.CurrentCharge = netCharge;
+                var changeEv = new ChargeChangedEvent(netCharge, bat.MaxCharge);
+                RaiseLocalEvent(uid, ref changeEv);
             }
         }
 
@@ -101,7 +110,61 @@ namespace Content.Server.Power.EntitySystems
         private void OnEmpPulse(EntityUid uid, BatteryComponent component, ref EmpPulseEvent args)
         {
             args.Affected = true;
-            component.UseCharge(args.EnergyConsumption);
+            UseCharge(uid, args.EnergyConsumption, component);
+        }
+
+        public float UseCharge(EntityUid uid, float value, BatteryComponent? battery = null)
+        {
+            if (value <= 0 ||  !Resolve(uid, ref battery) || battery.CurrentCharge == 0)
+                return 0;
+
+            var newValue = Math.Clamp(0, battery.CurrentCharge - value, battery._maxCharge);
+            var delta = newValue - battery.Charge;
+            battery.Charge = newValue;
+            var ev = new ChargeChangedEvent(battery.CurrentCharge, battery._maxCharge);
+            RaiseLocalEvent(uid, ref ev);
+            return delta;
+        }
+
+        public void SetMaxCharge(EntityUid uid, float value, BatteryComponent? battery = null)
+        {
+            if (!Resolve(uid, ref battery))
+                return;
+
+            var old = battery._maxCharge;
+            battery._maxCharge = Math.Max(value, 0);
+            battery.Charge = Math.Min(battery.Charge, battery._maxCharge);
+            if (MathHelper.CloseTo(battery._maxCharge, old))
+                return;
+
+            var ev = new ChargeChangedEvent(battery.CurrentCharge, battery._maxCharge);
+            RaiseLocalEvent(uid, ref ev);
+        }
+
+        public void SetCharge(EntityUid uid, float value, BatteryComponent? battery = null)
+        {
+            if (!Resolve(uid, ref battery))
+                return;
+
+            var old = battery.Charge;
+            battery.Charge = MathHelper.Clamp(value, 0, battery._maxCharge);
+            if (MathHelper.CloseTo(battery.Charge, old))
+                return;
+
+            var ev = new ChargeChangedEvent(battery.CurrentCharge, battery._maxCharge);
+            RaiseLocalEvent(uid, ref ev);
+        }
+
+        /// <summary>
+        ///     If sufficient charge is available on the battery, use it. Otherwise, don't.
+        /// </summary>
+        public bool TryUseCharge(EntityUid uid, float value, BatteryComponent? battery = null)
+        {
+            if (!Resolve(uid, ref battery, false) || value > battery.Charge)
+                return false;
+
+            UseCharge(uid, value, battery);
+            return true;
         }
     }
 }
index c199c6beb86237d3dd606b1c65d07d8a0705b02b..f7882dd6442d5378ccd4cc097e7ee38c5bff9bfc 100644 (file)
@@ -66,7 +66,7 @@ public sealed class PowerCellSystem : SharedPowerCellSystem
         Explode(uid, component, args.User);
     }
 
-    private void OnChargeChanged(EntityUid uid, PowerCellComponent component, ChargeChangedEvent args)
+    private void OnChargeChanged(EntityUid uid, PowerCellComponent component, ref ChargeChangedEvent args)
     {
         if (component.IsRigged)
         {
@@ -74,13 +74,10 @@ public sealed class PowerCellSystem : SharedPowerCellSystem
             return;
         }
 
-        if (!TryComp(uid, out BatteryComponent? battery))
-            return;
-
         if (!TryComp(uid, out AppearanceComponent? appearance))
             return;
 
-        var frac = battery.CurrentCharge / battery.MaxCharge;
+        var frac = args.Charge / args.MaxCharge;
         var level = (byte) ContentHelpers.RoundToNearestLevels(frac, 1, PowerCellComponent.PowerCellVisualsLevels);
         _sharedAppearanceSystem.SetData(uid, PowerCellVisuals.ChargeLevel, level, appearance);
 
index 5c4dd90dabe719b5c873408b3c254eda850806ed..39482048c944e2445b1900796b95d047dd62a407 100644 (file)
@@ -32,9 +32,9 @@ public sealed partial class GunSystem
         UpdateShots(uid, component);
     }
 
-    private void OnBatteryChargeChange(EntityUid uid, BatteryAmmoProviderComponent component, ChargeChangedEvent args)
+    private void OnBatteryChargeChange(EntityUid uid, BatteryAmmoProviderComponent component, ref ChargeChangedEvent args)
     {
-        UpdateShots(uid, component);
+        UpdateShots(uid, component, args.Charge, args.MaxCharge);
     }
 
     private void UpdateShots(EntityUid uid, BatteryAmmoProviderComponent component)
@@ -42,13 +42,13 @@ public sealed partial class GunSystem
         if (!TryComp<BatteryComponent>(uid, out var battery))
             return;
 
-        UpdateShots(uid, component, battery);
+        UpdateShots(uid, component, battery.Charge, battery.MaxCharge);
     }
 
-    private void UpdateShots(EntityUid uid, BatteryAmmoProviderComponent component, BatteryComponent battery)
+    private void UpdateShots(EntityUid uid, BatteryAmmoProviderComponent component, float charge, float maxCharge)
     {
-        var shots = (int) (battery.CurrentCharge / component.FireCost);
-        var maxShots = (int) (battery.MaxCharge / component.FireCost);
+        var shots = (int) (charge / component.FireCost);
+        var maxShots = (int) (maxCharge / component.FireCost);
 
         if (component.Shots != shots || component.Capacity != maxShots)
         {
@@ -128,10 +128,7 @@ public sealed partial class GunSystem
 
     protected override void TakeCharge(EntityUid uid, BatteryAmmoProviderComponent component)
     {
-        if (!TryComp<BatteryComponent>(uid, out var battery))
-            return;
-
-        battery.CurrentCharge -= component.FireCost;
-        UpdateShots(uid, component, battery);
+        // Will raise ChargeChangedEvent
+        _battery.UseCharge(uid, component.FireCost);
     }
 }
index 5868a45086e496920b7e9cd808be53621ff0a6c5..3eaf9d8bf451a19d7976e0101135adbfadfac0a0 100644 (file)
@@ -3,6 +3,7 @@ using Content.Server.Administration.Logs;
 using Content.Server.Cargo.Systems;
 using Content.Server.Examine;
 using Content.Server.Interaction;
+using Content.Server.Power.EntitySystems;
 using Content.Server.Stunnable;
 using Content.Server.Weapons.Ranged.Components;
 using Content.Shared.Damage;
@@ -37,6 +38,8 @@ public sealed partial class GunSystem : SharedGunSystem
     [Dependency] private readonly StaminaSystem _stamina = default!;
     [Dependency] private readonly StunSystem _stun = default!;
     [Dependency] private readonly SharedTransformSystem _transform = default!;
+    [Dependency] private readonly BatterySystem _battery = default!;
+
 
     public const float DamagePitchVariation = SharedMeleeWeaponSystem.DamagePitchVariation;
     public const float GunClumsyChance = 0.5f;