-using Content.Shared.Chemistry.Components.SolutionManager;
-using Content.Shared.FixedPoint;
-using Content.Shared.Tools.Components;
-
-using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem;
+using Content.Shared.Tools.Systems;
namespace Content.Server.Tools;
-public sealed class ToolSystem : SharedToolSystem
-{
- public override void Update(float frameTime)
- {
- base.Update(frameTime);
-
- UpdateWelders(frameTime);
- }
-
- //todo move to shared once you can remove reagents from shared without it freaking out.
- private void UpdateWelders(float frameTime)
- {
- var query = EntityQueryEnumerator<WelderComponent, SolutionContainerManagerComponent>();
- while (query.MoveNext(out var uid, out var welder, out var solutionContainer))
- {
- if (!welder.Enabled)
- continue;
-
- welder.WelderTimer += frameTime;
-
- if (welder.WelderTimer < welder.WelderUpdateTimer)
- continue;
-
- if (!SolutionContainerSystem.TryGetSolution((uid, solutionContainer), welder.FuelSolutionName, out var solutionComp, out var solution))
- continue;
-
- SolutionContainerSystem.RemoveReagent(solutionComp.Value, welder.FuelReagent, welder.FuelConsumption * welder.WelderTimer);
-
- if (solution.GetTotalPrototypeQuantity(welder.FuelReagent) <= FixedPoint2.Zero)
- {
- ItemToggle.Toggle(uid, predicted: false);
- }
-
- Dirty(uid, welder);
- welder.WelderTimer -= welder.WelderUpdateTimer;
- }
- }
-}
-
+public sealed class ToolSystem : SharedToolSystem;
-using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using Content.Shared.Tools.Systems;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared.Tools.Components;
-[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), Access(typeof(SharedToolSystem))]
+/// <summary>
+/// Handles fuel consumption for the tool and allows it to explode welding fuel tanks.
+/// </summary>
+/// <summary>
+/// TODO: De-hardcode welder bombing.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), AutoGenerateComponentPause]
+[Access(typeof(SharedToolSystem))]
public sealed partial class WelderComponent : Component
{
+ /// <summary>
+ /// Is the welder currently enabled?
+ /// </summary>
[DataField, AutoNetworkedField]
public bool Enabled;
+ /// <summary>
+ /// Timestamp for the next update loop update.
+ /// </summary>
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ [AutoNetworkedField, AutoPausedField]
+ public TimeSpan NextUpdate;
+
+ /// <summary>
+ /// Delay between updates.
+ /// </summary>
[DataField]
- public float WelderTimer;
+ public TimeSpan WelderUpdateTimer = TimeSpan.FromSeconds(1);
/// <summary>
- /// Name of <see cref="FuelSolution"/>.
+ /// Name of the fuel solution.
/// </summary>
[DataField]
public string FuelSolutionName = "Welder";
/// <summary>
- /// Reagent that will be used as fuel for welding.
+ /// Reagent that will be used as fuel for welding.
/// </summary>
[DataField]
public ProtoId<ReagentPrototype> FuelReagent = "WeldingFuel";
/// <summary>
- /// Fuel consumption per second while the welder is active.
+ /// Fuel consumption per second while the welder is active.
+ /// In u/s
/// </summary>
[DataField, AutoNetworkedField]
public FixedPoint2 FuelConsumption = FixedPoint2.New(1.0f);
/// <summary>
- /// A fuel amount to be consumed when the welder goes from being unlit to being lit.
+ /// A fuel amount to be consumed when the welder goes from being unlit to being lit.
/// </summary>
[DataField, AutoNetworkedField]
public FixedPoint2 FuelLitCost = FixedPoint2.New(0.5f);
/// <summary>
- /// Sound played when refilling the welder.
+ /// Sound played when refilling the welder.
/// </summary>
[DataField]
public SoundSpecifier WelderRefill = new SoundPathSpecifier("/Audio/Effects/refill.ogg");
/// <summary>
- /// Whether the item is safe to refill while lit without exploding the tank.
+ /// Whether the item is safe to refill while lit without exploding the tank.
/// </summary>
[DataField]
public bool TankSafe;
-
- [DataField]
- public float WelderUpdateTimer = 1f;
}
public void InitializeWelder()
{
+ SubscribeLocalEvent<WelderComponent, MapInitEvent>(OnWelderInit);
SubscribeLocalEvent<WelderComponent, ExaminedEvent>(OnWelderExamine);
SubscribeLocalEvent<WelderComponent, AfterInteractEvent>(OnWelderAfterInteract);
- SubscribeLocalEvent<WelderComponent, ToolUseAttemptEvent>((uid, comp, ev) => {
+ SubscribeLocalEvent<WelderComponent, ToolUseAttemptEvent>((uid, comp, ev) =>
+ {
CanCancelWelderUse((uid, comp), ev.User, ev.Fuel, ev);
});
- SubscribeLocalEvent<WelderComponent, DoAfterAttemptEvent<ToolDoAfterEvent>>((uid, comp, ev) => {
+ SubscribeLocalEvent<WelderComponent, DoAfterAttemptEvent<ToolDoAfterEvent>>((uid, comp, ev) =>
+ {
CanCancelWelderUse((uid, comp), ev.Event.User, ev.Event.Fuel, ev);
});
SubscribeLocalEvent<WelderComponent, ToolDoAfterEvent>(OnWelderDoAfter);
return (fuelSolution.GetTotalPrototypeQuantity(welder.FuelReagent), fuelSolution.MaxVolume);
}
+ private void OnWelderInit(Entity<WelderComponent> ent, ref MapInitEvent args)
+ {
+ ent.Comp.NextUpdate = _timing.CurTime + ent.Comp.WelderUpdateTimer;
+ Dirty(ent);
+ }
+
private void OnWelderExamine(Entity<WelderComponent> entity, ref ExaminedEvent args)
{
using (args.PushGroup(nameof(WelderComponent)))
private void OnActivateAttempt(Entity<WelderComponent> entity, ref ItemToggleActivateAttemptEvent args)
{
- if (args.User != null && !_actionBlocker.CanComplexInteract(args.User.Value)) {
+ if (args.User != null && !_actionBlocker.CanComplexInteract(args.User.Value))
+ {
args.Cancelled = true;
return;
}
private void OnDeactivateAttempt(Entity<WelderComponent> entity, ref ItemToggleDeactivateAttemptEvent args)
{
- if (args.User != null && !_actionBlocker.CanComplexInteract(args.User.Value)) {
+ if (args.User != null && !_actionBlocker.CanComplexInteract(args.User.Value))
+ {
args.Cancelled = true;
- return;
+ }
+ }
+
+ private void UpdateWelders()
+ {
+ var query = EntityQueryEnumerator<WelderComponent, SolutionContainerManagerComponent>();
+ var curTime = _timing.CurTime;
+ while (query.MoveNext(out var uid, out var welder, out var solutionContainer))
+ {
+ if (curTime < welder.NextUpdate)
+ continue;
+
+ welder.NextUpdate += welder.WelderUpdateTimer;
+ Dirty(uid, welder);
+
+ if (!welder.Enabled)
+ continue;
+
+ if (!SolutionContainerSystem.TryGetSolution((uid, solutionContainer), welder.FuelSolutionName, out var solutionComp, out var solution))
+ continue;
+
+ SolutionContainerSystem.RemoveReagent(solutionComp.Value, welder.FuelReagent, welder.FuelConsumption * welder.WelderUpdateTimer.TotalSeconds);
+
+ if (solution.GetTotalPrototypeQuantity(welder.FuelReagent) <= FixedPoint2.Zero)
+ ItemToggle.Toggle(uid);
}
}
}
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
+using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Shared.Tools.Systems;
public abstract partial class SharedToolSystem : EntitySystem
{
+ [Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IPrototypeManager _protoMan = default!;
[Dependency] protected readonly ISharedAdminLogManager AdminLogger = default!;
return !beforeAttempt.Cancelled;
}
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ UpdateWelders();
+ }
+
#region DoAfterEvents
[Serializable, NetSerializable]