private bool TryGetStartProgress(out float progress)
{
+ // Try to check progress of auto-revving first
+ if (_entityManager.TryGetComponent<ActiveGeneratorRevvingComponent>(_entity, out var activeGeneratorRevvingComponent) && _entityManager.TryGetComponent<PortableGeneratorComponent>(_entity, out var portableGeneratorComponent))
+ {
+ var calculatedProgress = activeGeneratorRevvingComponent.CurrentTime / portableGeneratorComponent.StartTime;
+ progress = (float) calculatedProgress;
+ return true;
+ }
+
var doAfterSystem = _entityManager.EntitySysManager.GetEntitySystem<DoAfterSystem>();
return doAfterSystem.TryFindActiveDoAfter<GeneratorStartedEvent>(_entity, out _, out _, out progress);
}
--- /dev/null
+using Content.Shared.DeviceLinking;
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Power.Generator;
+
+/// <summary>
+/// When attached to an entity with <see cref="FuelGeneratorComponent"/> it will allow the signal network to exert control over the generator.
+/// </summary>
+[RegisterComponent]
+public sealed partial class GeneratorSignalControlComponent: Component
+{
+ /// <summary>
+ /// The port that should be invoked when turning the generator on.
+ /// </summary>
+ [DataField]
+ public ProtoId<SinkPortPrototype> OnPort = "On";
+
+ /// <summary>
+ /// The port that should be invoked when turning the generator off.
+ /// </summary>
+ [DataField]
+ public ProtoId<SinkPortPrototype> OffPort = "Off";
+
+ /// <summary>
+ /// The port that should be invoked when toggling the generator.
+ /// </summary>
+ [DataField]
+ public ProtoId<SinkPortPrototype> TogglePort = "Toggle";
+}
--- /dev/null
+using System.ComponentModel;
+using Content.Server.DeviceLinking.Events;
+using Content.Shared.Power.Generator;
+
+namespace Content.Server.Power.Generator;
+
+public sealed class GeneratorSignalControlSystem: EntitySystem
+{
+ [Dependency] private readonly GeneratorSystem _generator = default!;
+ [Dependency] private readonly ActiveGeneratorRevvingSystem _revving = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent<GeneratorSignalControlComponent, SignalReceivedEvent>(OnSignalReceived);
+ }
+
+ /// <summary>
+ /// Change the state of the generator depending on what signal is sent.
+ /// </summary>
+ private void OnSignalReceived(EntityUid uid, GeneratorSignalControlComponent component, SignalReceivedEvent args)
+ {
+ if (!TryComp<FuelGeneratorComponent>(uid, out var generator))
+ return;
+
+ if (args.Port == component.OnPort)
+ {
+ _revving.StartAutoRevving(uid);
+ }
+ else if (args.Port == component.OffPort)
+ {
+ _generator.SetFuelGeneratorOn(uid, false, generator);
+ _revving.StopAutoRevving(uid);
+ }
+ else if (args.Port == component.TogglePort)
+ {
+ if (generator.On)
+ {
+ _generator.SetFuelGeneratorOn(uid, false, generator);
+ _revving.StopAutoRevving(uid);
+ }
+ else
+ {
+ _revving.StartAutoRevving(uid);
+ }
+ }
+ }
+}
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly GeneratorSystem _generator = default!;
[Dependency] private readonly PowerSwitchableSystem _switchable = default!;
+ [Dependency] private readonly ActiveGeneratorRevvingSystem _revving = default!;
[Dependency] private readonly PowerNetSystem _powerNet = default!;
public override void Initialize()
UpdatesAfter.Add(typeof(PowerNetSystem));
SubscribeLocalEvent<PortableGeneratorComponent, GetVerbsEvent<AlternativeVerb>>(GetAlternativeVerb);
- SubscribeLocalEvent<PortableGeneratorComponent, GeneratorStartedEvent>(GeneratorTugged);
+ SubscribeLocalEvent<PortableGeneratorComponent, GeneratorStartedEvent>(OnGeneratorStarted);
+ SubscribeLocalEvent<PortableGeneratorComponent, AutoGeneratorStartedEvent>(OnAutoGeneratorStarted);
SubscribeLocalEvent<PortableGeneratorComponent, PortableGeneratorStartMessage>(GeneratorStartMessage);
SubscribeLocalEvent<PortableGeneratorComponent, PortableGeneratorStopMessage>(GeneratorStopMessage);
SubscribeLocalEvent<PortableGeneratorComponent, PortableGeneratorSwitchOutputMessage>(GeneratorSwitchOutputMessage);
_generator.SetFuelGeneratorOn(uid, false);
}
- private void GeneratorTugged(EntityUid uid, PortableGeneratorComponent component, GeneratorStartedEvent args)
+ private void OnGeneratorStarted(EntityUid uid, PortableGeneratorComponent component, GeneratorStartedEvent args)
{
- if (args.Cancelled || !Transform(uid).Anchored)
+ if (args.Cancelled)
+ return;
+
+ GeneratorTugged(uid, component, args.User, out args.Repeat);
+ }
+
+ private void OnAutoGeneratorStarted(EntityUid uid, PortableGeneratorComponent component, ref AutoGeneratorStartedEvent args)
+ {
+ GeneratorTugged(uid, component, null, out var repeat);
+
+ // restart the auto rev if it should be repeated
+ if (repeat)
+ _revving.StartAutoRevving(uid);
+ else
+ args.Started = true;
+ }
+
+ private void GeneratorTugged(EntityUid uid, PortableGeneratorComponent component, EntityUid? user, out bool repeat)
+ {
+ repeat = false;
+
+ if (!Transform(uid).Anchored)
return;
var fuelGenerator = Comp<FuelGeneratorComponent>(uid);
if (!clogged && !empty && _random.Prob(component.StartChance))
{
- _popup.PopupEntity(Loc.GetString("portable-generator-start-success"), uid, args.User);
_generator.SetFuelGeneratorOn(uid, true, fuelGenerator);
+
+ if (user is null)
+ return;
+
+ _popup.PopupEntity(Loc.GetString("portable-generator-start-success"), uid, user.Value);
+
}
else
{
- _popup.PopupEntity(Loc.GetString("portable-generator-start-fail"), uid, args.User);
- // Try again bozo
- args.Repeat = true;
+ // try again bozo
+ repeat = true;
+
+ if (user is null)
+ return;
+
+ _popup.PopupEntity(Loc.GetString("portable-generator-start-fail"), uid, user.Value);
}
}
--- /dev/null
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Power.Generator;
+
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class ActiveGeneratorRevvingComponent: Component
+{
+ [DataField, ViewVariables(VVAccess.ReadOnly), AutoNetworkedField]
+ public TimeSpan CurrentTime = TimeSpan.Zero;
+}
--- /dev/null
+using Content.Shared.DoAfter;
+
+namespace Content.Shared.Power.Generator;
+
+public sealed class ActiveGeneratorRevvingSystem: EntitySystem
+{
+ [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
+ [Dependency] private readonly EntityManager _entity = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent<ActiveGeneratorRevvingComponent, AnchorStateChangedEvent>(OnAnchorStateChanged);
+ }
+
+ /// <summary>
+ /// Handles the AnchorStateChangedEvent to stop auto-revving when unanchored.
+ /// </summary>
+ private void OnAnchorStateChanged(EntityUid uid, ActiveGeneratorRevvingComponent component, AnchorStateChangedEvent args)
+ {
+ if (!args.Anchored)
+ StopAutoRevving(uid);
+ }
+
+ /// <summary>
+ /// Start revving a generator entity automatically, without another entity doing a do-after.
+ /// Used for remotely activating a generator.
+ /// </summary>
+ /// <param name="uid">Uid of the generator entity.</param>
+ /// <param name="component">ActiveGeneratorRevvingComponent of the generator entity.</param>
+ public void StartAutoRevving(EntityUid uid, ActiveGeneratorRevvingComponent? component = null)
+ {
+ if (Resolve(uid, ref component))
+ {
+ // reset the revving
+ component.CurrentTime = TimeSpan.FromSeconds(0);
+ return;
+ }
+
+ AddComp(uid, new ActiveGeneratorRevvingComponent());
+ }
+
+ /// <summary>
+ /// Stop revving a generator entity.
+ /// </summary>
+ /// <param name="uid">Uid of the generator entity.</param>
+ /// <returns>True if the auto-revving was cancelled, false if it was never revving in the first place.</returns>
+ public bool StopAutoRevving(EntityUid uid)
+ {
+ return RemComp<ActiveGeneratorRevvingComponent>(uid);
+ }
+
+ /// <summary>
+ /// Raise an event on a generator entity to start it.
+ /// </summary>
+ /// <remarks>This is not the same as revving it, when this is called the generator will start producing power.</remarks>
+ /// <param name="uid">Uid of the generator entity.</param>
+ /// <returns>True if the generator was successfully started, false otherwise.</returns>
+ private bool StartGenerator(EntityUid uid)
+ {
+ var ev = new AutoGeneratorStartedEvent();
+ RaiseLocalEvent(uid, ref ev);
+ return ev.Started;
+ }
+
+ /// <summary>
+ /// Updates the timers on ActiveGeneratorRevvingComponent(s), and stops them when they are finished.
+ /// </summary>
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+ var query = EntityQueryEnumerator<ActiveGeneratorRevvingComponent, PortableGeneratorComponent>();
+
+ while (query.MoveNext(out var uid, out var activeGeneratorRevvingComponent, out var portableGeneratorComponent))
+ {
+ activeGeneratorRevvingComponent.CurrentTime += TimeSpan.FromSeconds(frameTime);
+ Dirty(uid, activeGeneratorRevvingComponent);
+
+ if (activeGeneratorRevvingComponent.CurrentTime < portableGeneratorComponent.StartTime)
+ continue;
+
+ if (StartGenerator(uid))
+ StopAutoRevving(uid);
+ }
+ }
+}
return this;
}
}
+
+/// <summary>
+/// Used to start a portable generator. This is like <see cref="GeneratorStartedEvent"/> except it isn't a do-after.
+/// </summary>
+[ByRefEvent]
+public sealed partial class AutoGeneratorStartedEvent
+{
+ public bool Started = false;
+}
supplyRampRate: 500
supplyRampTolerance: 500
enabled: false
+ - type: DeviceLinkSink
+ ports:
+ - On
+ - Off
+ - Toggle
+ - type: GeneratorSignalControl
+ - type: DeviceNetwork
+ deviceNetId: Wireless
+ receiveFrequencyId: BasicDevice
+ - type: WirelessNetworkConnection
+ range: 200
- type: entity
abstract: true