From fe1044bedd51b24113626585d423f3ba7c95da84 Mon Sep 17 00:00:00 2001 From: Just-a-Unity-Dev Date: Fri, 22 Jul 2022 16:18:32 +0800 Subject: [PATCH 1/2] Carrying port from Nyanotrasen --- .../2G2C/Carrying/BeingCarriedComponent.cs | 11 + .../2G2C/Carrying/CarriableComponent.cs | 16 ++ .../2G2C/Carrying/CarryingComponent.cs | 9 + .../2G2C/Carrying/CarryingSystem.cs | 229 ++++++++++++++++++ 4 files changed, 265 insertions(+) create mode 100644 Content.Server/2G2C/Carrying/BeingCarriedComponent.cs create mode 100644 Content.Server/2G2C/Carrying/CarriableComponent.cs create mode 100644 Content.Server/2G2C/Carrying/CarryingComponent.cs create mode 100644 Content.Server/2G2C/Carrying/CarryingSystem.cs diff --git a/Content.Server/2G2C/Carrying/BeingCarriedComponent.cs b/Content.Server/2G2C/Carrying/BeingCarriedComponent.cs new file mode 100644 index 000000000..6b9a071d5 --- /dev/null +++ b/Content.Server/2G2C/Carrying/BeingCarriedComponent.cs @@ -0,0 +1,11 @@ +namespace Content.Server.Carrying +{ + /// + /// Used so we can sub to events like VirtualItemDeleted + /// + [RegisterComponent] + public sealed class BeingCarriedComponent : Component + { + public EntityUid Carrier = default!; + } +} diff --git a/Content.Server/2G2C/Carrying/CarriableComponent.cs b/Content.Server/2G2C/Carrying/CarriableComponent.cs new file mode 100644 index 000000000..420c2417d --- /dev/null +++ b/Content.Server/2G2C/Carrying/CarriableComponent.cs @@ -0,0 +1,16 @@ +using System.Threading; + +namespace Content.Server.Carrying +{ + [RegisterComponent] + public sealed class CarriableComponent : Component + { + public CancellationTokenSource? CancelToken; + /// + /// Number of free hands required + /// to carry the entity + /// + [DataField("freeHandsRequired")] + public int FreeHandsRequired = 2; + } +} diff --git a/Content.Server/2G2C/Carrying/CarryingComponent.cs b/Content.Server/2G2C/Carrying/CarryingComponent.cs new file mode 100644 index 000000000..f51717ab1 --- /dev/null +++ b/Content.Server/2G2C/Carrying/CarryingComponent.cs @@ -0,0 +1,9 @@ +namespace Content.Server.Carrying +{ + /// + /// Used so we can sub to events like VirtualItemDeleted + /// + [RegisterComponent] + public sealed class CarryingComponent : Component + {} +} diff --git a/Content.Server/2G2C/Carrying/CarryingSystem.cs b/Content.Server/2G2C/Carrying/CarryingSystem.cs new file mode 100644 index 000000000..1dabf5da8 --- /dev/null +++ b/Content.Server/2G2C/Carrying/CarryingSystem.cs @@ -0,0 +1,229 @@ +using System.Threading; +using Content.Server.DoAfter; +using Content.Server.Hands.Systems; +using Content.Server.Hands.Components; +using Content.Shared.MobState.Components; +using Content.Shared.Hands.Components; +using Content.Shared.Hands; +using Content.Shared.Stunnable; +using Content.Shared.Interaction.Events; +using Content.Shared.Verbs; +using Content.Shared.Carrying; +using Content.Shared.Movement.Events; +using Content.Shared.Pulling; +using Content.Shared.Pulling.Components; +using Content.Shared.Standing; +using Content.Shared.ActionBlocker; +using Robust.Shared.Physics; + +namespace Content.Server.Carrying +{ + public sealed class CarryingSystem : EntitySystem + { + [Dependency] private readonly HandVirtualItemSystem _virtualItemSystem = default!; + [Dependency] private readonly CarryingSlowdownSystem _slowdown = default!; + [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly StandingStateSystem _standingState = default!; + [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; + [Dependency] private readonly SharedPullingSystem _pullingSystem = default!; + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent>(AddCarryVerb); + SubscribeLocalEvent(OnVirtualItemDeleted); + SubscribeLocalEvent(OnMoveAttempt); + SubscribeLocalEvent(OnStandAttempt); + SubscribeLocalEvent(OnInteractedWith); + SubscribeLocalEvent(OnCarrySuccess); + SubscribeLocalEvent(OnCarryCancelled); + } + + + private void AddCarryVerb(EntityUid uid, CarriableComponent component, GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess) + return; + + if (!CanCarry(args.User, uid, component)) + return; + + if (HasComp(args.User)) // yeah not dealing with that + return; + + if (!HasComp(uid) && !(TryComp(uid, out var state) && (state.IsCritical() || state.IsDead() || state.IsIncapacitated()))) + return; + + AlternativeVerb verb = new() + { + Act = () => + { + StartCarryDoAfter(args.User, uid, component); + }, + Text = Loc.GetString("carry-verb"), + Priority = 2 + }; + args.Verbs.Add(verb); + } + + private void OnVirtualItemDeleted(EntityUid uid, CarryingComponent component, VirtualItemDeletedEvent args) + { + if (!HasComp(args.BlockingEntity)) + return; + + DropCarried(uid, args.BlockingEntity); + } + + private void OnMoveAttempt(EntityUid uid, BeingCarriedComponent component, UpdateCanMoveEvent args) + { + args.Cancel(); + } + + private void OnStandAttempt(EntityUid uid, BeingCarriedComponent component, StandAttemptEvent args) + { + args.Cancel(); + } + + private void OnInteractedWith(EntityUid uid, BeingCarriedComponent component, GettingInteractedWithAttemptEvent args) + { + if (args.Uid != component.Carrier) + args.Cancel(); + } + + private void OnCarrySuccess(CarrySuccessfulEvent ev) + { + if (!CanCarry(ev.Carrier, ev.Carried, ev.Component)) + return; + + Carry(ev.Carrier, ev.Carried); + } + + private void OnCarryCancelled(CarryCancelledEvent ev) + { + if (ev.Component == null) + return; + + ev.Component.CancelToken = null; + } + + private void StartCarryDoAfter(EntityUid carrier, EntityUid carried, CarriableComponent component) + { + if (component.CancelToken != null) + { + component.CancelToken.Cancel(); + component.CancelToken = null; + } + + component.CancelToken = new CancellationTokenSource(); + _doAfterSystem.DoAfter(new DoAfterEventArgs(carrier, 3f, component.CancelToken.Token, target: carried) + { + BroadcastFinishedEvent = new CarrySuccessfulEvent(carrier, carried, component), + BroadcastCancelledEvent = new CarryCancelledEvent(carrier, component), + BreakOnTargetMove = true, + BreakOnUserMove = true, + BreakOnStun = true, + NeedHand = true + }); + } + + private void Carry(EntityUid carrier, EntityUid carried) + { + if (TryComp(carried, out var pullable)) + _pullingSystem.TryStopPull(pullable); + + Transform(carried).Coordinates = Transform(carrier).Coordinates; + Transform(carried).ParentUid = carrier; + _virtualItemSystem.TrySpawnVirtualItemInHand(carried, carrier); + _virtualItemSystem.TrySpawnVirtualItemInHand(carried, carrier); + EnsureComp(carrier); + ApplyCarrySlowdown(carrier, carried); + var carriedComp = EnsureComp(carried); + carriedComp.Carrier = carrier; + _actionBlockerSystem.UpdateCanMove(carried); + } + + public void DropCarried(EntityUid carrier, EntityUid carried) + { + RemComp(carrier); // get rid of this first so we don't recusrively fire that event + RemComp(carrier); + RemComp(carried); + _actionBlockerSystem.UpdateCanMove(carried); + _virtualItemSystem.DeleteInHandsMatching(carrier, carried); + Transform(carried).AttachToGridOrMap(); + _standingState.Stand(carried); + } + + private void ApplyCarrySlowdown(EntityUid carrier, EntityUid carried) + { + if (!TryComp(carrier, out var carrierFixtures)) + return; + if (!TryComp(carried, out var carriedFixtures)) + return; + if (carrierFixtures.Fixtures.Count == 0 || carriedFixtures.Fixtures.Count == 0) + return; + + float carrierMass = 0f; + float carriedMass = 0f; + foreach (var fixture in carrierFixtures.Fixtures.Values) + { + carrierMass += fixture.Mass; + } + foreach (var fixture in carriedFixtures.Fixtures.Values) + { + carriedMass += fixture.Mass; + } + + if (carrierMass == 0f) + carrierMass = 70f; + if (carriedMass == 0f) + carriedMass = 70f; + + var massRatioSq = Math.Pow((carriedMass / carrierMass), 2); + var modifier = (1 - (massRatioSq * 0.15)); + var slowdownComp = EnsureComp(carrier); + _slowdown.SetModifier(carrier, (float) modifier, (float) modifier, slowdownComp); + } + + public bool CanCarry(EntityUid carrier, EntityUid carried, CarriableComponent? carriedComp = null) + { + if (!Resolve(carried, ref carriedComp)) + return false; + + if (!TryComp(carrier, out var hands)) + return false; + + if (hands.CountFreeHands() < carriedComp.FreeHandsRequired) + return false; + + return true; + } + + private sealed class CarryCancelledEvent : EntityEventArgs + { + public EntityUid Uid; + + public CarriableComponent Component; + + public CarryCancelledEvent(EntityUid uid, CarriableComponent component) + { + Uid = uid; + Component = component; + } + } + + private sealed class CarrySuccessfulEvent : EntityEventArgs + { + public EntityUid Carrier; + + public EntityUid Carried; + + public CarriableComponent Component; + + public CarrySuccessfulEvent(EntityUid carrier, EntityUid carried, CarriableComponent component) + { + Carrier = carrier; + Carried = carried; + Component = component; + } + } + } +} From 1b93f2e17e27fe2e48fe43374b91ff231277d9b7 Mon Sep 17 00:00:00 2001 From: Just-a-Unity-Dev Date: Fri, 22 Jul 2022 16:28:34 +0800 Subject: [PATCH 2/2] Import this other one --- .../Carrying/CarryingSlowdownComponent.cs | 28 +++++++++++ .../2G2C/Carrying/CarryingSlowdownSystem.cs | 47 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 Content.Shared/2G2C/Carrying/CarryingSlowdownComponent.cs create mode 100644 Content.Shared/2G2C/Carrying/CarryingSlowdownSystem.cs diff --git a/Content.Shared/2G2C/Carrying/CarryingSlowdownComponent.cs b/Content.Shared/2G2C/Carrying/CarryingSlowdownComponent.cs new file mode 100644 index 000000000..f9913c36a --- /dev/null +++ b/Content.Shared/2G2C/Carrying/CarryingSlowdownComponent.cs @@ -0,0 +1,28 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared.Carrying +{ + [RegisterComponent, NetworkedComponent, Access(typeof(CarryingSlowdownSystem))] + + public sealed class CarryingSlowdownComponent : Component + { + [DataField("walkModifier", required: true)] [ViewVariables(VVAccess.ReadWrite)] + public float WalkModifier = 1.0f; + + [DataField("sprintModifier", required: true)] [ViewVariables(VVAccess.ReadWrite)] + public float SprintModifier = 1.0f; + } + + [Serializable, NetSerializable] + public sealed class CarryingSlowdownComponentState : ComponentState + { + public float WalkModifier; + public float SprintModifier; + public CarryingSlowdownComponentState(float walkModifier, float sprintModifier) + { + WalkModifier = walkModifier; + SprintModifier = sprintModifier; + } + } +} \ No newline at end of file diff --git a/Content.Shared/2G2C/Carrying/CarryingSlowdownSystem.cs b/Content.Shared/2G2C/Carrying/CarryingSlowdownSystem.cs new file mode 100644 index 000000000..e9f167b68 --- /dev/null +++ b/Content.Shared/2G2C/Carrying/CarryingSlowdownSystem.cs @@ -0,0 +1,47 @@ +using Content.Shared.Movement.Systems; +using Robust.Shared.GameStates; + +namespace Content.Shared.Carrying +{ + public sealed class CarryingSlowdownSystem : EntitySystem + { + [Dependency] private readonly MovementSpeedModifierSystem _movementSpeed = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnGetState); + SubscribeLocalEvent(OnHandleState); + SubscribeLocalEvent(OnRefreshMoveSpeed); + } + + public void SetModifier(EntityUid uid, float walkSpeedModifier, float sprintSpeedModifier, CarryingSlowdownComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + component.WalkModifier = walkSpeedModifier; + component.SprintModifier = sprintSpeedModifier; + _movementSpeed.RefreshMovementSpeedModifiers(uid); + } + private void OnGetState(EntityUid uid, CarryingSlowdownComponent component, ref ComponentGetState args) + { + args.State = new CarryingSlowdownComponentState(component.WalkModifier, component.SprintModifier); + } + + private void OnHandleState(EntityUid uid, CarryingSlowdownComponent component, ref ComponentHandleState args) + { + if (args.Current is CarryingSlowdownComponentState state) + { + component.WalkModifier = state.WalkModifier; + component.SprintModifier = state.SprintModifier; + + _movementSpeed.RefreshMovementSpeedModifiers(uid); + } + } + private void OnRefreshMoveSpeed(EntityUid uid, CarryingSlowdownComponent component, RefreshMovementSpeedModifiersEvent args) + { + args.ModifySpeed(component.WalkModifier, component.SprintModifier); + } + } +} \ No newline at end of file