From da1007b7f1eaf3e83cf9958151de35ab491e8599 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Mon, 7 Feb 2022 00:34:13 +1100 Subject: [PATCH] Chem injectors ECS (#6366) --- .../Chemistry/Components/InjectorComponent.cs | 334 +-------------- .../EntitySystems/ChemistrySystem.Injector.cs | 385 ++++++++++++++++++ .../EntitySystems/ChemistrySystem.cs | 25 ++ ...ySystem.cs => ChemistrySystemHypospray.cs} | 8 +- .../Chemistry/EntitySystems/InjectorSystem.cs | 34 -- .../Components/SharedInjectorComponent.cs | 11 +- 6 files changed, 421 insertions(+), 376 deletions(-) create mode 100644 Content.Server/Chemistry/EntitySystems/ChemistrySystem.Injector.cs create mode 100644 Content.Server/Chemistry/EntitySystems/ChemistrySystem.cs rename Content.Server/Chemistry/EntitySystems/{HypospraySystem.cs => ChemistrySystemHypospray.cs} (89%) delete mode 100644 Content.Server/Chemistry/EntitySystems/InjectorSystem.cs diff --git a/Content.Server/Chemistry/Components/InjectorComponent.cs b/Content.Server/Chemistry/Components/InjectorComponent.cs index 532bf4537b..79ac277de2 100644 --- a/Content.Server/Chemistry/Components/InjectorComponent.cs +++ b/Content.Server/Chemistry/Components/InjectorComponent.cs @@ -34,10 +34,8 @@ namespace Content.Server.Chemistry.Components /// containers, and can directly inject into a mobs bloodstream. /// [RegisterComponent] - public class InjectorComponent : SharedInjectorComponent, IAfterInteract, IUse + public class InjectorComponent : SharedInjectorComponent { - [Dependency] private readonly IEntityManager _entities = default!; - public const string SolutionName = "injector"; /// @@ -46,7 +44,7 @@ namespace Content.Server.Chemistry.Components /// [ViewVariables] [DataField("injectOnly")] - private bool _injectOnly; + public bool InjectOnly; /// /// Amount to inject or draw on each usage. If the injector is inject only, it will @@ -54,7 +52,7 @@ namespace Content.Server.Chemistry.Components /// [ViewVariables(VVAccess.ReadWrite)] [DataField("transferAmount")] - private FixedPoint2 _transferAmount = FixedPoint2.New(5); + public FixedPoint2 TransferAmount = FixedPoint2.New(5); /// /// Injection delay (seconds) when the target is a mob. @@ -90,331 +88,5 @@ namespace Content.Server.Chemistry.Components Dirty(); } } - - protected override void Startup() - { - base.Startup(); - - Dirty(); - } - - /// - /// Toggle between draw/inject state if applicable - /// - private void Toggle(EntityUid user) - { - if (_injectOnly) - { - return; - } - - string msg; - switch (ToggleState) - { - case InjectorToggleMode.Inject: - ToggleState = InjectorToggleMode.Draw; - msg = "injector-component-drawing-text"; - break; - case InjectorToggleMode.Draw: - ToggleState = InjectorToggleMode.Inject; - msg = "injector-component-injecting-text"; - break; - default: - throw new ArgumentOutOfRangeException(); - } - - Owner.PopupMessage(user, Loc.GetString(msg)); - } - - /// - /// Called when clicking on entities while holding in active hand - /// - /// - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) - { - if (CancelToken != null) - { - CancelToken.Cancel(); - return true; - } - - if (!eventArgs.CanReach) - return false; - - var solutionsSys = EntitySystem.Get(); - //Make sure we have the attacking entity - if (eventArgs.Target is not {Valid: true} target || - !_entities.HasComponent(Owner)) - { - return false; - } - - // Is the target a mob? If yes, use a do-after to give them time to respond. - if (_entities.HasComponent(target) || - _entities.HasComponent(target)) - { - if (!await TryInjectDoAfter(eventArgs.User, target)) - return true; - } - - // Handle injecting/drawing for solutions - if (ToggleState == InjectorToggleMode.Inject) - { - if (solutionsSys.TryGetInjectableSolution(target, out var injectableSolution)) - { - TryInject(target, injectableSolution, eventArgs.User, false); - } - else if (solutionsSys.TryGetRefillableSolution(target, out var refillableSolution)) - { - TryInject(target, refillableSolution, eventArgs.User, true); - } - else if (_entities.TryGetComponent(target, out BloodstreamComponent? bloodstream)) - { - TryInjectIntoBloodstream(bloodstream, eventArgs.User); - } - else - { - eventArgs.User.PopupMessage(eventArgs.User, - Loc.GetString("injector-component-cannot-transfer-message", - ("target", target))); - } - } - else if (ToggleState == InjectorToggleMode.Draw) - { - if (solutionsSys.TryGetDrawableSolution(target, out var drawableSolution)) - { - TryDraw(target, drawableSolution, eventArgs.User); - } - else - { - eventArgs.User.PopupMessage(eventArgs.User, - Loc.GetString("injector-component-cannot-draw-message", - ("target", target))); - } - } - - return true; - } - - /// - /// Send informative pop-up messages and wait for a do-after to complete. - /// - public async Task TryInjectDoAfter(EntityUid user, EntityUid target) - { - var popupSys = EntitySystem.Get(); - - // Create a pop-up for the user - popupSys.PopupEntity(Loc.GetString("injector-component-injecting-user"), target, Filter.Entities(user)); - - if (!EntitySystem.Get().TryGetSolution(Owner, SolutionName, out var solution)) - return false; - - // Get entity for logging. Log with EntityUids when? - var logSys = EntitySystem.Get(); - - var actualDelay = MathF.Max(Delay, 1f); - if (user != target) - { - // Create a pop-up for the target - var userName = _entities.GetComponent(user).EntityName; - popupSys.PopupEntity(Loc.GetString("injector-component-injecting-target", - ("user", userName)), user, Filter.Entities(target)); - - // Check if the target is incapacitated or in combat mode and modify time accordingly. - if (_entities.TryGetComponent(target, out var mobState) && - mobState.IsIncapacitated()) - { - actualDelay /= 2; - } - else if (_entities.TryGetComponent(target, out var combat) && - combat.IsInCombatMode) - { - // Slightly increase the delay when the target is in combat mode. Helps prevents cheese injections in - // combat with fast syringes & lag. - actualDelay += 1; - } - - // Add an admin log, using the "force feed" log type. It's not quite feeding, but the effect is the same. - if (ToggleState == InjectorToggleMode.Inject) - { - logSys.Add(LogType.ForceFeed, - $"{_entities.ToPrettyString(user):user} is attempting to inject {_entities.ToPrettyString(target):target} with a solution {SolutionContainerSystem.ToPrettyString(solution):solution}"); - // TODO solution pretty string. - } - } - else - { - // Self-injections take half as long. - actualDelay /= 2; - - if (ToggleState == InjectorToggleMode.Inject) - logSys.Add(LogType.Ingestion, - $"{_entities.ToPrettyString(user):user} is attempting to inject themselves with a solution {SolutionContainerSystem.ToPrettyString(solution):solution}."); - //TODO solution pretty string. - } - - CancelToken = new(); - var status = await EntitySystem.Get().WaitDoAfter( - new DoAfterEventArgs(user, actualDelay, CancelToken.Token, target) - { - BreakOnUserMove = true, - BreakOnDamage = true, - BreakOnStun = true, - BreakOnTargetMove = true, - MovementThreshold = 1.0f - }); - CancelToken = null; - - return status == DoAfterStatus.Finished; - } - - /// - /// Called when use key is pressed when held in active hand - /// - /// - /// - bool IUse.UseEntity(UseEntityEventArgs eventArgs) - { - Toggle(eventArgs.User); - return true; - } - - private void TryInjectIntoBloodstream(BloodstreamComponent targetBloodstream, EntityUid user) - { - // Get transfer amount. May be smaller than _transferAmount if not enough room - var realTransferAmount = FixedPoint2.Min(_transferAmount, targetBloodstream.Solution.AvailableVolume); - - if (realTransferAmount <= 0) - { - Owner.PopupMessage(user, - Loc.GetString("injector-component-cannot-inject-message", ("target", targetBloodstream.Owner))); - return; - } - - // Move units from attackSolution to targetSolution - var removedSolution = - EntitySystem.Get().SplitSolution(user, targetBloodstream.Solution, realTransferAmount); - - var bloodstreamSys = EntitySystem.Get(); - bloodstreamSys.TryAddToBloodstream((targetBloodstream).Owner, removedSolution, targetBloodstream); - - removedSolution.DoEntityReaction(targetBloodstream.Owner, ReactionMethod.Injection); - - Owner.PopupMessage(user, - Loc.GetString("injector-component-inject-success-message", - ("amount", removedSolution.TotalVolume), - ("target", targetBloodstream.Owner))); - Dirty(); - AfterInject(); - } - - private void TryInject(EntityUid targetEntity, Solution targetSolution, EntityUid user, bool asRefill) - { - if (!EntitySystem.Get().TryGetSolution(Owner, SolutionName, out var solution) - || solution.CurrentVolume == 0) - { - return; - } - - // Get transfer amount. May be smaller than _transferAmount if not enough room - var realTransferAmount = FixedPoint2.Min(_transferAmount, targetSolution.AvailableVolume); - - if (realTransferAmount <= 0) - { - Owner.PopupMessage(user, - Loc.GetString("injector-component-target-already-full-message", ("target", targetEntity))); - return; - } - - // Move units from attackSolution to targetSolution - var removedSolution = EntitySystem.Get().SplitSolution(Owner, solution, realTransferAmount); - - removedSolution.DoEntityReaction(targetEntity, ReactionMethod.Injection); - - if (!asRefill) - { - EntitySystem.Get() - .Inject(targetEntity, targetSolution, removedSolution); - } - else - { - EntitySystem.Get() - .Refill(targetEntity, targetSolution, removedSolution); - } - - Owner.PopupMessage(user, - Loc.GetString("injector-component-transfer-success-message", - ("amount", removedSolution.TotalVolume), - ("target", targetEntity))); - Dirty(); - AfterInject(); - } - - private void AfterInject() - { - // Automatically set syringe to draw after completely draining it. - if (EntitySystem.Get().TryGetSolution(Owner, SolutionName, out var solution) - && solution.CurrentVolume == 0) - { - ToggleState = InjectorToggleMode.Draw; - } - } - - private void AfterDraw() - { - // Automatically set syringe to inject after completely filling it. - if (EntitySystem.Get().TryGetSolution(Owner, SolutionName, out var solution) - && solution.AvailableVolume == 0) - { - ToggleState = InjectorToggleMode.Inject; - } - } - - private void TryDraw(EntityUid targetEntity, Solution targetSolution, EntityUid user) - { - if (!EntitySystem.Get().TryGetSolution(Owner, SolutionName, out var solution) - || solution.AvailableVolume == 0) - { - return; - } - - // Get transfer amount. May be smaller than _transferAmount if not enough room - var realTransferAmount = FixedPoint2.Min(_transferAmount, targetSolution.DrawAvailable); - - if (realTransferAmount <= 0) - { - Owner.PopupMessage(user, - Loc.GetString("injector-component-target-is-empty-message", ("target", targetEntity))); - return; - } - - // Move units from attackSolution to targetSolution - var removedSolution = EntitySystem.Get() - .Draw(targetEntity, targetSolution, realTransferAmount); - - if (!EntitySystem.Get().TryAddSolution(targetEntity, solution, removedSolution)) - { - return; - } - - Owner.PopupMessage(user, - Loc.GetString("injector-component-draw-success-message", - ("amount", removedSolution.TotalVolume), - ("target", targetEntity))); - Dirty(); - AfterDraw(); - } - - - public override ComponentState GetComponentState() - { - _entities.EntitySysManager.GetEntitySystem() - .TryGetSolution(Owner, SolutionName, out var solution); - - var currentVolume = solution?.CurrentVolume ?? FixedPoint2.Zero; - var maxVolume = solution?.MaxVolume ?? FixedPoint2.Zero; - - return new InjectorComponentState(currentVolume, maxVolume, ToggleState); - } } } diff --git a/Content.Server/Chemistry/EntitySystems/ChemistrySystem.Injector.cs b/Content.Server/Chemistry/EntitySystems/ChemistrySystem.Injector.cs new file mode 100644 index 0000000000..870278cac6 --- /dev/null +++ b/Content.Server/Chemistry/EntitySystems/ChemistrySystem.Injector.cs @@ -0,0 +1,385 @@ +using System; +using System.Threading; +using Content.Server.Body.Components; +using Content.Server.Chemistry.Components; +using Content.Server.Chemistry.Components.SolutionManager; +using Content.Server.CombatMode; +using Content.Server.DoAfter; +using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.Database; +using Content.Shared.FixedPoint; +using Content.Shared.Hands; +using Content.Shared.Interaction; +using Content.Shared.Interaction.Helpers; +using Content.Shared.MobState.Components; +using Robust.Shared.GameObjects; +using Robust.Shared.GameStates; +using Robust.Shared.Localization; +using Robust.Shared.Player; + +namespace Content.Server.Chemistry.EntitySystems; + +public sealed partial class ChemistrySystem +{ + private void InitializeInjector() + { + SubscribeLocalEvent(OnSolutionChange); + SubscribeLocalEvent(OnInjectorDeselected); + SubscribeLocalEvent(OnInjectorStartup); + SubscribeLocalEvent(OnInjectorUse); + SubscribeLocalEvent(OnInjectorAfterInteract); + SubscribeLocalEvent(OnInjectorGetState); + + SubscribeLocalEvent(OnInjectionComplete); + SubscribeLocalEvent(OnInjectionCancelled); + } + + private static void OnInjectionCancelled(InjectionCancelledEvent ev) + { + ev.Component.CancelToken = null; + } + + private void OnInjectionComplete(InjectionCompleteEvent ev) + { + var component = ev.Component; + var user = ev.User; + var target = ev.Target; + + component.CancelToken = null; + + // Handle injecting/drawing for solutions + if (component.ToggleState == SharedInjectorComponent.InjectorToggleMode.Inject) + { + if (_solutions.TryGetInjectableSolution(target, out var injectableSolution)) + { + TryInject(component, target, injectableSolution, user, false); + } + else if (_solutions.TryGetRefillableSolution(target, out var refillableSolution)) + { + TryInject(component, target, refillableSolution, user, true); + } + else if (TryComp(target, out var bloodstream)) + { + TryInjectIntoBloodstream(component, bloodstream, user); + } + else + { + _popup.PopupEntity(Loc.GetString("injector-component-cannot-transfer-message", + ("target", target)), component.Owner, Filter.Entities(user)); + } + } + else if (component.ToggleState == SharedInjectorComponent.InjectorToggleMode.Draw) + { + if (_solutions.TryGetDrawableSolution(target, out var drawableSolution)) + { + TryDraw(component, target, drawableSolution, user); + } + else + { + _popup.PopupEntity(Loc.GetString("injector-component-cannot-draw-message", + ("target", target)), component.Owner, Filter.Entities(user)); + } + } + } + + private static void OnInjectorDeselected(EntityUid uid, InjectorComponent component, HandDeselectedEvent args) + { + component.CancelToken?.Cancel(); + component.CancelToken = null; + } + + private void OnSolutionChange(EntityUid uid, InjectorComponent component, SolutionChangedEvent args) + { + Dirty(component); + } + + private void OnInjectorGetState(EntityUid uid, InjectorComponent component, ref ComponentGetState args) + { + _solutions.TryGetSolution(uid, InjectorComponent.SolutionName, out var solution); + + var currentVolume = solution?.CurrentVolume ?? FixedPoint2.Zero; + var maxVolume = solution?.MaxVolume ?? FixedPoint2.Zero; + + args.State = new SharedInjectorComponent.InjectorComponentState(currentVolume, maxVolume, component.ToggleState); + } + + private void OnInjectorAfterInteract(EntityUid uid, InjectorComponent component, AfterInteractEvent args) + { + if (args.Handled || !args.CanReach) return; + + if (component.CancelToken != null) + { + component.CancelToken.Cancel(); + component.CancelToken = null; + args.Handled = true; + return; + } + + if (!_blocker.CanInteract(args.User)) + return; + + //Make sure we have the attacking entity + if (args.Target is not { Valid: true } target || + !HasComp(uid)) + { + return; + } + + // Is the target a mob? If yes, use a do-after to give them time to respond. + if (HasComp(target) || + HasComp(target)) + { + InjectDoAfter(component, args.User, target); + args.Handled = true; + return; + } + } + + private void OnInjectorStartup(EntityUid uid, InjectorComponent component, ComponentStartup args) + { + Dirty(component); + } + + private void OnInjectorUse(EntityUid uid, InjectorComponent component, UseInHandEvent args) + { + if (args.Handled) return; + + Toggle(component, args.User); + args.Handled = true; + } + + /// + /// Toggle between draw/inject state if applicable + /// + private void Toggle(InjectorComponent component, EntityUid user) + { + if (component.InjectOnly) + { + return; + } + + string msg; + switch (component.ToggleState) + { + case SharedInjectorComponent.InjectorToggleMode.Inject: + component.ToggleState = SharedInjectorComponent.InjectorToggleMode.Draw; + msg = "injector-component-drawing-text"; + break; + case SharedInjectorComponent.InjectorToggleMode.Draw: + component.ToggleState = SharedInjectorComponent.InjectorToggleMode.Inject; + msg = "injector-component-injecting-text"; + break; + default: + throw new ArgumentOutOfRangeException(); + } + + _popup.PopupEntity(Loc.GetString(msg), component.Owner, Filter.Entities(user)); + } + + /// + /// Send informative pop-up messages and wait for a do-after to complete. + /// + private void InjectDoAfter(InjectorComponent component, EntityUid user, EntityUid target) + { + // Create a pop-up for the user + _popup.PopupEntity(Loc.GetString("injector-component-injecting-user"), target, Filter.Entities(user)); + + if (!_solutions.TryGetSolution(component.Owner, InjectorComponent.SolutionName, out var solution)) + return; + + // Get entity for logging. Log with EntityUids when? + var actualDelay = MathF.Max(component.Delay, 1f); + if (user != target) + { + // Create a pop-up for the target + var userName = MetaData(user).EntityName; + _popup.PopupEntity(Loc.GetString("injector-component-injecting-target", + ("user", userName)), user, Filter.Entities(target)); + + // Check if the target is incapacitated or in combat mode and modify time accordingly. + if (TryComp(target, out var mobState) && mobState.IsIncapacitated()) + { + actualDelay /= 2; + } + else if (TryComp(target, out var combat) && combat.IsInCombatMode) + { + // Slightly increase the delay when the target is in combat mode. Helps prevents cheese injections in + // combat with fast syringes & lag. + actualDelay += 1; + } + + // Add an admin log, using the "force feed" log type. It's not quite feeding, but the effect is the same. + if (component.ToggleState == SharedInjectorComponent.InjectorToggleMode.Inject) + { + _logs.Add(LogType.ForceFeed, + $"{EntityManager.ToPrettyString(user):user} is attempting to inject {EntityManager.ToPrettyString(target):target} with a solution {SolutionContainerSystem.ToPrettyString(solution):solution}"); + // TODO solution pretty string. + } + } + else + { + // Self-injections take half as long. + actualDelay /= 2; + + if (component.ToggleState == SharedInjectorComponent.InjectorToggleMode.Inject) + _logs.Add(LogType.Ingestion, + $"{EntityManager.ToPrettyString(user):user} is attempting to inject themselves with a solution {SolutionContainerSystem.ToPrettyString(solution):solution}."); + //TODO solution pretty string. + } + + component.CancelToken = new CancellationTokenSource(); + + _doAfter.DoAfter(new DoAfterEventArgs(user, actualDelay, component.CancelToken.Token, target) + { + BreakOnUserMove = true, + BreakOnDamage = true, + BreakOnStun = true, + BreakOnTargetMove = true, + MovementThreshold = 0.1f, + BroadcastFinishedEvent = new InjectionCompleteEvent() + { + Component = component, + User = user, + Target = target, + }, + BroadcastCancelledEvent = new InjectionCancelledEvent() + { + Component = component, + } + }); + } + + private void TryInjectIntoBloodstream(InjectorComponent component, BloodstreamComponent targetBloodstream, EntityUid user) + { + // Get transfer amount. May be smaller than _transferAmount if not enough room + var realTransferAmount = FixedPoint2.Min(component.TransferAmount, targetBloodstream.Solution.AvailableVolume); + + if (realTransferAmount <= 0) + { + _popup.PopupEntity(Loc.GetString("injector-component-cannot-inject-message", ("target", targetBloodstream.Owner)), + component.Owner, Filter.Entities(user)); + return; + } + + // Move units from attackSolution to targetSolution + var removedSolution = _solutions.SplitSolution(user, targetBloodstream.Solution, realTransferAmount); + + _blood.TryAddToBloodstream((targetBloodstream).Owner, removedSolution, targetBloodstream); + + removedSolution.DoEntityReaction(targetBloodstream.Owner, ReactionMethod.Injection); + + _popup.PopupEntity(Loc.GetString("injector-component-inject-success-message", + ("amount", removedSolution.TotalVolume), + ("target", targetBloodstream.Owner)), component.Owner, Filter.Entities(user)); + + Dirty(component); + AfterInject(component); + } + + private void TryInject(InjectorComponent component, EntityUid targetEntity, Solution targetSolution, EntityUid user, bool asRefill) + { + if (!_solutions.TryGetSolution(component.Owner, InjectorComponent.SolutionName, out var solution) + || solution.CurrentVolume == 0) + { + return; + } + + // Get transfer amount. May be smaller than _transferAmount if not enough room + var realTransferAmount = FixedPoint2.Min(component.TransferAmount, targetSolution.AvailableVolume); + + if (realTransferAmount <= 0) + { + _popup.PopupEntity(Loc.GetString("injector-component-target-already-full-message", ("target", targetEntity)), + component.Owner, Filter.Entities(user)); + return; + } + + // Move units from attackSolution to targetSolution + var removedSolution = _solutions.SplitSolution(component.Owner, solution, realTransferAmount); + + removedSolution.DoEntityReaction(targetEntity, ReactionMethod.Injection); + + if (!asRefill) + { + _solutions.Inject(targetEntity, targetSolution, removedSolution); + } + else + { + _solutions.Refill(targetEntity, targetSolution, removedSolution); + } + + _popup.PopupEntity(Loc.GetString("injector-component-transfer-success-message", + ("amount", removedSolution.TotalVolume), + ("target", targetEntity)), component.Owner, Filter.Entities(user)); + + Dirty(component); + AfterInject(component); + } + + private void AfterInject(InjectorComponent component) + { + // Automatically set syringe to draw after completely draining it. + if (_solutions.TryGetSolution(component.Owner, InjectorComponent.SolutionName, out var solution) + && solution.CurrentVolume == 0) + { + component.ToggleState = SharedInjectorComponent.InjectorToggleMode.Draw; + } + } + + private void AfterDraw(InjectorComponent component) + { + // Automatically set syringe to inject after completely filling it. + if (_solutions.TryGetSolution(component.Owner, InjectorComponent.SolutionName, out var solution) + && solution.AvailableVolume == 0) + { + component.ToggleState = SharedInjectorComponent.InjectorToggleMode.Inject; + } + } + + private void TryDraw(InjectorComponent component, EntityUid targetEntity, Solution targetSolution, EntityUid user) + { + if (!_solutions.TryGetSolution(component.Owner, InjectorComponent.SolutionName, out var solution) + || solution.AvailableVolume == 0) + { + return; + } + + // Get transfer amount. May be smaller than _transferAmount if not enough room + var realTransferAmount = FixedPoint2.Min(component.TransferAmount, targetSolution.DrawAvailable); + + if (realTransferAmount <= 0) + { + _popup.PopupEntity(Loc.GetString("injector-component-target-is-empty-message", ("target", targetEntity)), + component.Owner, Filter.Entities(user)); + return; + } + + // Move units from attackSolution to targetSolution + var removedSolution = _solutions.Draw(targetEntity, targetSolution, realTransferAmount); + + if (!_solutions.TryAddSolution(targetEntity, solution, removedSolution)) + { + return; + } + + _popup.PopupEntity(Loc.GetString("injector-component-draw-success-message", + ("amount", removedSolution.TotalVolume), + ("target", targetEntity)), component.Owner, Filter.Entities(user)); + + Dirty(component); + AfterDraw(component); + } + + private sealed class InjectionCompleteEvent : EntityEventArgs + { + public InjectorComponent Component { get; init; } = default!; + public EntityUid User { get; init; } + public EntityUid Target { get; init; } + } + + private sealed class InjectionCancelledEvent : EntityEventArgs + { + public InjectorComponent Component { get; init; } = default!; + } +} diff --git a/Content.Server/Chemistry/EntitySystems/ChemistrySystem.cs b/Content.Server/Chemistry/EntitySystems/ChemistrySystem.cs new file mode 100644 index 0000000000..cd194a1ad0 --- /dev/null +++ b/Content.Server/Chemistry/EntitySystems/ChemistrySystem.cs @@ -0,0 +1,25 @@ +using Content.Server.Administration.Logs; +using Content.Server.Body.Systems; +using Content.Server.DoAfter; +using Content.Server.Popups; +using Content.Shared.ActionBlocker; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; + +namespace Content.Server.Chemistry.EntitySystems; + +public sealed partial class ChemistrySystem : EntitySystem +{ + [Dependency] private readonly ActionBlockerSystem _blocker = default!; + [Dependency] private readonly AdminLogSystem _logs = default!; + [Dependency] private readonly BloodstreamSystem _blood = default!; + [Dependency] private readonly DoAfterSystem _doAfter = default!; + [Dependency] private readonly PopupSystem _popup = default!; + [Dependency] private readonly SolutionContainerSystem _solutions = default!; + + public override void Initialize() + { + InitializeHypospray(); + InitializeInjector(); + } +} diff --git a/Content.Server/Chemistry/EntitySystems/HypospraySystem.cs b/Content.Server/Chemistry/EntitySystems/ChemistrySystemHypospray.cs similarity index 89% rename from Content.Server/Chemistry/EntitySystems/HypospraySystem.cs rename to Content.Server/Chemistry/EntitySystems/ChemistrySystemHypospray.cs index e19151cb76..ab29879a7c 100644 --- a/Content.Server/Chemistry/EntitySystems/HypospraySystem.cs +++ b/Content.Server/Chemistry/EntitySystems/ChemistrySystemHypospray.cs @@ -6,13 +6,10 @@ using Robust.Shared.GameObjects; namespace Content.Server.Chemistry.EntitySystems { - [UsedImplicitly] - public class HypospraySystem : EntitySystem + public sealed partial class ChemistrySystem { - public override void Initialize() + private void InitializeHypospray() { - base.Initialize(); - SubscribeLocalEvent(OnAfterInteract); SubscribeLocalEvent(OnClickAttack); SubscribeLocalEvent(OnSolutionChange); @@ -27,6 +24,7 @@ namespace Content.Server.Chemistry.EntitySystems { if (!args.CanReach) return; + var target = args.Target; var user = args.User; diff --git a/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs b/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs deleted file mode 100644 index 06843489ce..0000000000 --- a/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Content.Server.Chemistry.Components; -using Content.Shared.Hands; -using JetBrains.Annotations; -using Robust.Shared.GameObjects; -using System; - -namespace Content.Server.Chemistry.EntitySystems -{ - [UsedImplicitly] - public class InjectorSystem : EntitySystem - { - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnSolutionChange); - SubscribeLocalEvent(OnInjectorDeselected); - } - - private void OnInjectorDeselected(EntityUid uid, InjectorComponent component, HandDeselectedEvent args) - { - if (component.CancelToken != null) - { - component.CancelToken.Cancel(); - component.CancelToken = null; - } - } - - private void OnSolutionChange(EntityUid uid, InjectorComponent component, SolutionChangedEvent args) - { - Dirty(component); - } - } -} diff --git a/Content.Shared/Chemistry/Components/SharedInjectorComponent.cs b/Content.Shared/Chemistry/Components/SharedInjectorComponent.cs index 60d009aebe..4b2fa63c21 100644 --- a/Content.Shared/Chemistry/Components/SharedInjectorComponent.cs +++ b/Content.Shared/Chemistry/Components/SharedInjectorComponent.cs @@ -1,5 +1,4 @@ using System; -using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using Robust.Shared.GameObjects; using Robust.Shared.GameStates; @@ -10,20 +9,20 @@ namespace Content.Shared.Chemistry.Components /// /// Shared class for injectors & syringes /// - [NetworkedComponent()] - public class SharedInjectorComponent : Component + [NetworkedComponent, ComponentProtoName("Injector")] + public abstract class SharedInjectorComponent : Component { /// /// Component data used for net updates. Used by client for item status ui /// [Serializable, NetSerializable] - protected sealed class InjectorComponentState : ComponentState + public sealed class InjectorComponentState : ComponentState { public FixedPoint2 CurrentVolume { get; } public FixedPoint2 TotalVolume { get; } public InjectorToggleMode CurrentMode { get; } - public InjectorComponentState(FixedPoint2 currentVolume, FixedPoint2 totalVolume, InjectorToggleMode currentMode) + public InjectorComponentState(FixedPoint2 currentVolume, FixedPoint2 totalVolume, SharedInjectorComponent.InjectorToggleMode currentMode) { CurrentVolume = currentVolume; TotalVolume = totalVolume; @@ -31,7 +30,7 @@ namespace Content.Shared.Chemistry.Components } } - public enum InjectorToggleMode + public enum InjectorToggleMode : byte { Inject, Draw