Emergency revert for pulling (#24923)
Revert "Pulling rework (#20906)"
This reverts commit 0d8254b2a2.
This commit is contained in:
@@ -4,7 +4,6 @@ using JetBrains.Annotations;
|
|||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Timing;
|
|
||||||
|
|
||||||
namespace Content.Client.Alerts;
|
namespace Content.Client.Alerts;
|
||||||
|
|
||||||
@@ -13,7 +12,6 @@ public sealed class ClientAlertsSystem : AlertsSystem
|
|||||||
{
|
{
|
||||||
public AlertOrderPrototype? AlertOrder { get; set; }
|
public AlertOrderPrototype? AlertOrder { get; set; }
|
||||||
|
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
|
||||||
@@ -42,7 +40,7 @@ public sealed class ClientAlertsSystem : AlertsSystem
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var ent = _playerManager.LocalEntity;
|
var ent = _playerManager.LocalPlayer?.ControlledEntity;
|
||||||
return ent is not null
|
return ent is not null
|
||||||
? GetActiveAlerts(ent.Value)
|
? GetActiveAlerts(ent.Value)
|
||||||
: null;
|
: null;
|
||||||
@@ -51,28 +49,29 @@ public sealed class ClientAlertsSystem : AlertsSystem
|
|||||||
|
|
||||||
protected override void AfterShowAlert(Entity<AlertsComponent> alerts)
|
protected override void AfterShowAlert(Entity<AlertsComponent> alerts)
|
||||||
{
|
{
|
||||||
UpdateHud(alerts);
|
if (_playerManager.LocalPlayer?.ControlledEntity != alerts.Owner)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SyncAlerts?.Invoke(this, alerts.Comp.Alerts);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void AfterClearAlert(Entity<AlertsComponent> alerts)
|
protected override void AfterClearAlert(Entity<AlertsComponent> alertsComponent)
|
||||||
{
|
{
|
||||||
UpdateHud(alerts);
|
if (_playerManager.LocalPlayer?.ControlledEntity != alertsComponent.Owner)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SyncAlerts?.Invoke(this, alertsComponent.Comp.Alerts);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClientAlertsHandleState(Entity<AlertsComponent> alerts, ref AfterAutoHandleStateEvent args)
|
private void ClientAlertsHandleState(EntityUid uid, AlertsComponent component, ref AfterAutoHandleStateEvent args)
|
||||||
{
|
{
|
||||||
UpdateHud(alerts);
|
if (_playerManager.LocalPlayer?.ControlledEntity == uid)
|
||||||
}
|
SyncAlerts?.Invoke(this, component.Alerts);
|
||||||
|
|
||||||
private void UpdateHud(Entity<AlertsComponent> entity)
|
|
||||||
{
|
|
||||||
if (_playerManager.LocalEntity == entity.Owner)
|
|
||||||
SyncAlerts?.Invoke(this, entity.Comp.Alerts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPlayerAttached(EntityUid uid, AlertsComponent component, LocalPlayerAttachedEvent args)
|
private void OnPlayerAttached(EntityUid uid, AlertsComponent component, LocalPlayerAttachedEvent args)
|
||||||
{
|
{
|
||||||
if (_playerManager.LocalEntity != uid)
|
if (_playerManager.LocalPlayer?.ControlledEntity != uid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SyncAlerts?.Invoke(this, component.Alerts);
|
SyncAlerts?.Invoke(this, component.Alerts);
|
||||||
@@ -82,7 +81,7 @@ public sealed class ClientAlertsSystem : AlertsSystem
|
|||||||
{
|
{
|
||||||
base.HandleComponentShutdown(uid, component, args);
|
base.HandleComponentShutdown(uid, component, args);
|
||||||
|
|
||||||
if (_playerManager.LocalEntity != uid)
|
if (_playerManager.LocalPlayer?.ControlledEntity != uid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ClearAlerts?.Invoke(this, EventArgs.Empty);
|
ClearAlerts?.Invoke(this, EventArgs.Empty);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using Content.Shared.Movement.Components;
|
using Content.Shared.Movement.Components;
|
||||||
using Content.Shared.Movement.Pulling.Components;
|
|
||||||
using Content.Shared.Movement.Systems;
|
using Content.Shared.Movement.Systems;
|
||||||
using Robust.Client.GameObjects;
|
using Content.Shared.Pulling.Components;
|
||||||
using Robust.Client.Physics;
|
using Robust.Client.Physics;
|
||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
using Robust.Shared.Physics.Components;
|
using Robust.Shared.Physics.Components;
|
||||||
@@ -25,7 +24,7 @@ namespace Content.Client.Physics.Controllers
|
|||||||
|
|
||||||
SubscribeLocalEvent<InputMoverComponent, UpdateIsPredictedEvent>(OnUpdatePredicted);
|
SubscribeLocalEvent<InputMoverComponent, UpdateIsPredictedEvent>(OnUpdatePredicted);
|
||||||
SubscribeLocalEvent<MovementRelayTargetComponent, UpdateIsPredictedEvent>(OnUpdateRelayTargetPredicted);
|
SubscribeLocalEvent<MovementRelayTargetComponent, UpdateIsPredictedEvent>(OnUpdateRelayTargetPredicted);
|
||||||
SubscribeLocalEvent<PullableComponent, UpdateIsPredictedEvent>(OnUpdatePullablePredicted);
|
SubscribeLocalEvent<SharedPullableComponent, UpdateIsPredictedEvent>(OnUpdatePullablePredicted);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUpdatePredicted(EntityUid uid, InputMoverComponent component, ref UpdateIsPredictedEvent args)
|
private void OnUpdatePredicted(EntityUid uid, InputMoverComponent component, ref UpdateIsPredictedEvent args)
|
||||||
@@ -41,7 +40,7 @@ namespace Content.Client.Physics.Controllers
|
|||||||
args.IsPredicted = true;
|
args.IsPredicted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUpdatePullablePredicted(EntityUid uid, PullableComponent component, ref UpdateIsPredictedEvent args)
|
private void OnUpdatePullablePredicted(EntityUid uid, SharedPullableComponent component, ref UpdateIsPredictedEvent args)
|
||||||
{
|
{
|
||||||
// Enable prediction if an entity is being pulled by the player.
|
// Enable prediction if an entity is being pulled by the player.
|
||||||
// Disable prediction if an entity is being pulled by some non-player entity.
|
// Disable prediction if an entity is being pulled by some non-player entity.
|
||||||
|
|||||||
21
Content.Client/Pulling/PullingSystem.cs
Normal file
21
Content.Client/Pulling/PullingSystem.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using Content.Shared.Pulling;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Client.Physics;
|
||||||
|
|
||||||
|
namespace Content.Client.Pulling
|
||||||
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
|
public sealed class PullingSystem : SharedPullingSystem
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
UpdatesAfter.Add(typeof(PhysicsSystem));
|
||||||
|
|
||||||
|
SubscribeLocalEvent<SharedPullableComponent, PullableMoveMessage>(OnPullableMove);
|
||||||
|
SubscribeLocalEvent<SharedPullableComponent, PullableStopMovingMessage>(OnPullableStopMove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ using Content.Shared.Interaction.Events;
|
|||||||
using Content.Shared.Inventory.Events;
|
using Content.Shared.Inventory.Events;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Content.Shared.Movement.Events;
|
using Content.Shared.Movement.Events;
|
||||||
using Content.Shared.Movement.Pulling.Events;
|
using Content.Shared.Physics.Pull;
|
||||||
using Content.Shared.Throwing;
|
using Content.Shared.Throwing;
|
||||||
|
|
||||||
namespace Content.Client.Replay.Spectator;
|
namespace Content.Client.Replay.Spectator;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public sealed class ThrownItemVisualizerSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnAutoHandleState(EntityUid uid, ThrownItemComponent component, ref AfterAutoHandleStateEvent args)
|
private void OnAutoHandleState(EntityUid uid, ThrownItemComponent component, ref AfterAutoHandleStateEvent args)
|
||||||
{
|
{
|
||||||
if (!TryComp<SpriteComponent>(uid, out var sprite) || !component.Animate)
|
if (!TryComp<SpriteComponent>(uid, out var sprite))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var animationPlayer = EnsureComp<AnimationPlayerComponent>(uid);
|
var animationPlayer = EnsureComp<AnimationPlayerComponent>(uid);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Content.Shared.Hands.Components;
|
using Content.Shared.Hands.Components;
|
||||||
using Content.Shared.Movement.Pulling.Components;
|
|
||||||
using Content.Shared.Prototypes;
|
using Content.Shared.Prototypes;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ public sealed class PullerTest
|
|||||||
{
|
{
|
||||||
foreach (var proto in protoManager.EnumeratePrototypes<EntityPrototype>())
|
foreach (var proto in protoManager.EnumeratePrototypes<EntityPrototype>())
|
||||||
{
|
{
|
||||||
if (!proto.TryGetComponent(out PullerComponent? puller))
|
if (!proto.TryGetComponent(out SharedPullerComponent? puller))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!puller.NeedsHands)
|
if (!puller.NeedsHands)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Movement.Pulling.Components;
|
using Content.Shared.Pulling.Components;
|
||||||
using Content.Shared.Movement.Pulling.Systems;
|
using Content.Shared.Pulling;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
namespace Content.Server.Alert.Click
|
namespace Content.Server.Alert.Click
|
||||||
@@ -20,9 +20,9 @@ namespace Content.Server.Alert.Click
|
|||||||
if (!entityManager.System<ActionBlockerSystem>().CanInteract(player, null))
|
if (!entityManager.System<ActionBlockerSystem>().CanInteract(player, null))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (entityManager.TryGetComponent(player, out PullableComponent? playerPullable))
|
if (entityManager.TryGetComponent(player, out SharedPullableComponent? playerPullable))
|
||||||
{
|
{
|
||||||
entityManager.System<PullingSystem>().TryStopPull(player, playerPullable, user: player);
|
entityManager.System<SharedPullingSystem>().TryStopPull(playerPullable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Movement.Pulling.Components;
|
using Content.Shared.Pulling;
|
||||||
using Content.Shared.Movement.Pulling.Systems;
|
using Content.Shared.Pulling.Components;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
namespace Content.Server.Alert.Click
|
namespace Content.Server.Alert.Click
|
||||||
@@ -15,12 +15,12 @@ namespace Content.Server.Alert.Click
|
|||||||
public void AlertClicked(EntityUid player)
|
public void AlertClicked(EntityUid player)
|
||||||
{
|
{
|
||||||
var entManager = IoCManager.Resolve<IEntityManager>();
|
var entManager = IoCManager.Resolve<IEntityManager>();
|
||||||
var ps = entManager.System<PullingSystem>();
|
|
||||||
|
|
||||||
if (entManager.TryGetComponent(player, out PullerComponent? puller) &&
|
var ps = entManager.System<SharedPullingSystem>();
|
||||||
entManager.TryGetComponent(puller.Pulling, out PullableComponent? pullableComp))
|
var playerTarget = ps.GetPulled(player);
|
||||||
|
if (playerTarget != default && entManager.TryGetComponent(playerTarget, out SharedPullableComponent? playerPullable))
|
||||||
{
|
{
|
||||||
ps.TryStopPull(puller.Pulling.Value, pullableComp, user: player);
|
ps.TryStopPull(playerPullable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ using Content.Shared.Jittering;
|
|||||||
using Content.Shared.Maps;
|
using Content.Shared.Maps;
|
||||||
using Content.Shared.Mobs;
|
using Content.Shared.Mobs;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
using Content.Shared.Speech.EntitySystems;
|
using Content.Shared.Speech.EntitySystems;
|
||||||
using Content.Shared.StatusEffect;
|
using Content.Shared.StatusEffect;
|
||||||
using Content.Shared.Stunnable;
|
using Content.Shared.Stunnable;
|
||||||
@@ -31,8 +32,6 @@ using Robust.Shared.Physics.Events;
|
|||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using PullableComponent = Content.Shared.Movement.Pulling.Components.PullableComponent;
|
|
||||||
using PullerComponent = Content.Shared.Movement.Pulling.Components.PullerComponent;
|
|
||||||
|
|
||||||
namespace Content.Server.Electrocution;
|
namespace Content.Server.Electrocution;
|
||||||
|
|
||||||
@@ -466,14 +465,14 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
|
|||||||
all.Add((entity, depth));
|
all.Add((entity, depth));
|
||||||
visited.Add(entity);
|
visited.Add(entity);
|
||||||
|
|
||||||
if (TryComp<PullableComponent>(entity, out var pullable) &&
|
if (TryComp<SharedPullableComponent>(entity, out var pullable) &&
|
||||||
pullable.Puller is { Valid: true } pullerId &&
|
pullable.Puller is { Valid: true } pullerId &&
|
||||||
!visited.Contains(pullerId))
|
!visited.Contains(pullerId))
|
||||||
{
|
{
|
||||||
GetChainedElectrocutionTargetsRecurse(pullerId, depth + 1, visited, all);
|
GetChainedElectrocutionTargetsRecurse(pullerId, depth + 1, visited, all);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryComp<PullerComponent>(entity, out var puller) &&
|
if (TryComp<SharedPullerComponent>(entity, out var puller) &&
|
||||||
puller.Pulling is { Valid: true } pullingId &&
|
puller.Pulling is { Valid: true } pullingId &&
|
||||||
!visited.Contains(pullingId))
|
!visited.Contains(pullingId))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Server.Inventory;
|
using Content.Server.Inventory;
|
||||||
|
using Content.Server.Pulling;
|
||||||
using Content.Server.Stack;
|
using Content.Server.Stack;
|
||||||
using Content.Server.Stunnable;
|
using Content.Server.Stunnable;
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
@@ -10,9 +11,8 @@ using Content.Shared.Hands.Components;
|
|||||||
using Content.Shared.Hands.EntitySystems;
|
using Content.Shared.Hands.EntitySystems;
|
||||||
using Content.Shared.Input;
|
using Content.Shared.Input;
|
||||||
using Content.Shared.Inventory.VirtualItem;
|
using Content.Shared.Inventory.VirtualItem;
|
||||||
using Content.Shared.Movement.Pulling.Components;
|
using Content.Shared.Physics.Pull;
|
||||||
using Content.Shared.Movement.Pulling.Events;
|
using Content.Shared.Pulling.Components;
|
||||||
using Content.Shared.Movement.Pulling.Systems;
|
|
||||||
using Content.Shared.Stacks;
|
using Content.Shared.Stacks;
|
||||||
using Content.Shared.Throwing;
|
using Content.Shared.Throwing;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
@@ -88,8 +88,9 @@ namespace Content.Server.Hands.Systems
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Break any pulls
|
// Break any pulls
|
||||||
if (TryComp(uid, out PullerComponent? puller) && TryComp(puller.Pulling, out PullableComponent? pullable))
|
if (TryComp(uid, out SharedPullerComponent? puller) && puller.Pulling is EntityUid pulled &&
|
||||||
_pullingSystem.TryStopPull(puller.Pulling.Value, pullable);
|
TryComp(pulled, out SharedPullableComponent? pullable))
|
||||||
|
_pullingSystem.TryStopPull(pullable);
|
||||||
|
|
||||||
if (!_handsSystem.TryDrop(uid, component.ActiveHand!, null, checkActionBlocker: false))
|
if (!_handsSystem.TryDrop(uid, component.ActiveHand!, null, checkActionBlocker: false))
|
||||||
return;
|
return;
|
||||||
@@ -127,13 +128,13 @@ namespace Content.Server.Hands.Systems
|
|||||||
|
|
||||||
private void HandlePullStarted(EntityUid uid, HandsComponent component, PullStartedMessage args)
|
private void HandlePullStarted(EntityUid uid, HandsComponent component, PullStartedMessage args)
|
||||||
{
|
{
|
||||||
if (args.PullerUid != uid)
|
if (args.Puller.Owner != uid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (TryComp<PullerComponent>(args.PullerUid, out var pullerComp) && !pullerComp.NeedsHands)
|
if (TryComp<SharedPullerComponent>(args.Puller.Owner, out var pullerComp) && !pullerComp.NeedsHands)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_virtualItemSystem.TrySpawnVirtualItemInHand(args.PulledUid, uid))
|
if (!_virtualItemSystem.TrySpawnVirtualItemInHand(args.Pulled.Owner, uid))
|
||||||
{
|
{
|
||||||
DebugTools.Assert("Unable to find available hand when starting pulling??");
|
DebugTools.Assert("Unable to find available hand when starting pulling??");
|
||||||
}
|
}
|
||||||
@@ -141,7 +142,7 @@ namespace Content.Server.Hands.Systems
|
|||||||
|
|
||||||
private void HandlePullStopped(EntityUid uid, HandsComponent component, PullStoppedMessage args)
|
private void HandlePullStopped(EntityUid uid, HandsComponent component, PullStoppedMessage args)
|
||||||
{
|
{
|
||||||
if (args.PullerUid != uid)
|
if (args.Puller.Owner != uid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Try find hand that is doing this pull.
|
// Try find hand that is doing this pull.
|
||||||
@@ -150,10 +151,8 @@ namespace Content.Server.Hands.Systems
|
|||||||
{
|
{
|
||||||
if (hand.HeldEntity == null
|
if (hand.HeldEntity == null
|
||||||
|| !TryComp(hand.HeldEntity, out VirtualItemComponent? virtualItem)
|
|| !TryComp(hand.HeldEntity, out VirtualItemComponent? virtualItem)
|
||||||
|| virtualItem.BlockingEntity != args.PulledUid)
|
|| virtualItem.BlockingEntity != args.Pulled.Owner)
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
QueueDel(hand.HeldEntity.Value);
|
QueueDel(hand.HeldEntity.Value);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Content.Shared.Pulling;
|
using Content.Shared.Pulling;
|
||||||
using PullingSystem = Content.Shared.Movement.Pulling.Systems.PullingSystem;
|
|
||||||
|
|
||||||
namespace Content.Server.NPC.HTN.Preconditions;
|
namespace Content.Server.NPC.HTN.Preconditions;
|
||||||
|
|
||||||
@@ -8,14 +7,14 @@ namespace Content.Server.NPC.HTN.Preconditions;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed partial class PulledPrecondition : HTNPrecondition
|
public sealed partial class PulledPrecondition : HTNPrecondition
|
||||||
{
|
{
|
||||||
private PullingSystem _pulling = default!;
|
private SharedPullingSystem _pulling = default!;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)] [DataField("isPulled")] public bool IsPulled = true;
|
[ViewVariables(VVAccess.ReadWrite)] [DataField("isPulled")] public bool IsPulled = true;
|
||||||
|
|
||||||
public override void Initialize(IEntitySystemManager sysManager)
|
public override void Initialize(IEntitySystemManager sysManager)
|
||||||
{
|
{
|
||||||
base.Initialize(sysManager);
|
base.Initialize(sysManager);
|
||||||
_pulling = sysManager.GetEntitySystem<PullingSystem>();
|
_pulling = sysManager.GetEntitySystem<SharedPullingSystem>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool IsMet(NPCBlackboard blackboard)
|
public override bool IsMet(NPCBlackboard blackboard)
|
||||||
|
|||||||
@@ -6,10 +6,11 @@ using Content.Shared.Objectives.Systems;
|
|||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
|
using Content.Shared.Objectives;
|
||||||
using Content.Shared.Mind.Components;
|
using Content.Shared.Mind.Components;
|
||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
using Content.Shared.Mobs.Components;
|
using Content.Shared.Mobs.Components;
|
||||||
using Content.Shared.Movement.Pulling.Components;
|
|
||||||
|
|
||||||
namespace Content.Server.Objectives.Systems;
|
namespace Content.Server.Objectives.Systems;
|
||||||
|
|
||||||
@@ -99,19 +100,19 @@ public sealed class StealConditionSystem : EntitySystem
|
|||||||
var count = 0;
|
var count = 0;
|
||||||
|
|
||||||
//check pulling object
|
//check pulling object
|
||||||
if (TryComp<PullerComponent>(mind.OwnedEntity, out var pull)) //TO DO: to make the code prettier? don't like the repetition
|
if (TryComp<SharedPullerComponent>(mind.OwnedEntity, out var pull)) //TO DO: to make the code prettier? don't like the repetition
|
||||||
{
|
{
|
||||||
var pulledEntity = pull.Pulling;
|
var pullid = pull.Pulling;
|
||||||
if (pulledEntity != null)
|
if (pullid != null)
|
||||||
{
|
{
|
||||||
// check if this is the item
|
// check if this is the item
|
||||||
if (CheckStealTarget(pulledEntity.Value, condition)) count++;
|
if (CheckStealTarget(pullid.Value, condition)) count++;
|
||||||
|
|
||||||
//we don't check the inventories of sentient entity
|
//we don't check the inventories of sentient entity
|
||||||
if (!HasComp<MindContainerComponent>(pulledEntity))
|
if (!TryComp<MindContainerComponent>(pullid, out var pullMind))
|
||||||
{
|
{
|
||||||
// if it is a container check its contents
|
// if it is a container check its contents
|
||||||
if (_containerQuery.TryGetComponent(pulledEntity, out var containerManager))
|
if (_containerQuery.TryGetComponent(pullid, out var containerManager))
|
||||||
stack.Push(containerManager);
|
stack.Push(containerManager);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
207
Content.Server/Physics/Controllers/PullController.cs
Normal file
207
Content.Server/Physics/Controllers/PullController.cs
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using Content.Shared.ActionBlocker;
|
||||||
|
using Content.Shared.Gravity;
|
||||||
|
using Content.Shared.Pulling;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
|
using Content.Shared.Rotatable;
|
||||||
|
using Robust.Shared.Physics;
|
||||||
|
using Robust.Shared.Physics.Components;
|
||||||
|
using Robust.Shared.Physics.Controllers;
|
||||||
|
|
||||||
|
namespace Content.Server.Physics.Controllers
|
||||||
|
{
|
||||||
|
public sealed class PullController : VirtualController
|
||||||
|
{
|
||||||
|
// Parameterization for pulling:
|
||||||
|
// Speeds. Note that the speed is mass-independent (multiplied by mass).
|
||||||
|
// Instead, tuning to mass is done via the mass values below.
|
||||||
|
// Note that setting the speed too high results in overshoots (stabilized by drag, but bad)
|
||||||
|
private const float AccelModifierHigh = 15f;
|
||||||
|
private const float AccelModifierLow = 60.0f;
|
||||||
|
// High/low-mass marks. Curve is constant-lerp-constant, i.e. if you can even pull an item,
|
||||||
|
// you'll always get at least AccelModifierLow and no more than AccelModifierHigh.
|
||||||
|
private const float AccelModifierHighMass = 70.0f; // roundstart saltern emergency closet
|
||||||
|
private const float AccelModifierLowMass = 5.0f; // roundstart saltern emergency crowbar
|
||||||
|
// Used to control settling (turns off pulling).
|
||||||
|
private const float MaximumSettleVelocity = 0.1f;
|
||||||
|
private const float MaximumSettleDistance = 0.1f;
|
||||||
|
// Settle shutdown control.
|
||||||
|
// Mustn't be too massive, as that causes severe mispredicts *and can prevent it ever resolving*.
|
||||||
|
// Exists to bleed off "I pulled my crowbar" overshoots.
|
||||||
|
// Minimum velocity for shutdown to be necessary. This prevents stuff getting stuck b/c too much shutdown.
|
||||||
|
private const float SettleMinimumShutdownVelocity = 0.25f;
|
||||||
|
// Distance in which settle shutdown multiplier is at 0. It then scales upwards linearly with closer distances.
|
||||||
|
private const float SettleShutdownDistance = 1.0f;
|
||||||
|
// Velocity change of -LinearVelocity * frameTime * this
|
||||||
|
private const float SettleShutdownMultiplier = 20.0f;
|
||||||
|
|
||||||
|
// How much you must move for the puller movement check to actually hit.
|
||||||
|
private const float MinimumMovementDistance = 0.005f;
|
||||||
|
|
||||||
|
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
|
||||||
|
[Dependency] private readonly SharedPullingSystem _pullableSystem = default!;
|
||||||
|
[Dependency] private readonly SharedGravitySystem _gravity = default!;
|
||||||
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
|
|
||||||
|
// TODO: Move this stuff to pullingsystem
|
||||||
|
/// <summary>
|
||||||
|
/// If distance between puller and pulled entity lower that this threshold,
|
||||||
|
/// pulled entity will not change its rotation.
|
||||||
|
/// Helps with small distance jittering
|
||||||
|
/// </summary>
|
||||||
|
private const float ThresholdRotDistance = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If difference between puller and pulled angle lower that this threshold,
|
||||||
|
/// pulled entity will not change its rotation.
|
||||||
|
/// Helps with diagonal movement jittering
|
||||||
|
/// As of further adjustments, should divide cleanly into 90 degrees
|
||||||
|
/// </summary>
|
||||||
|
private const float ThresholdRotAngle = 22.5f;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
UpdatesAfter.Add(typeof(MoverController));
|
||||||
|
SubscribeLocalEvent<SharedPullerComponent, MoveEvent>(OnPullerMove);
|
||||||
|
|
||||||
|
base.Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPullerMove(EntityUid uid, SharedPullerComponent component, ref MoveEvent args)
|
||||||
|
{
|
||||||
|
if (component.Pulling is not { } pullable || !TryComp<SharedPullableComponent>(pullable, out var pullableComponent))
|
||||||
|
return;
|
||||||
|
|
||||||
|
UpdatePulledRotation(uid, pullable);
|
||||||
|
|
||||||
|
if (args.NewPosition.EntityId == args.OldPosition.EntityId &&
|
||||||
|
(args.NewPosition.Position - args.OldPosition.Position).LengthSquared() < MinimumMovementDistance * MinimumMovementDistance)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (TryComp<PhysicsComponent>(pullable, out var physics))
|
||||||
|
PhysicsSystem.WakeBody(pullable, body: physics);
|
||||||
|
|
||||||
|
_pullableSystem.StopMoveTo(pullableComponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdatePulledRotation(EntityUid puller, EntityUid pulled)
|
||||||
|
{
|
||||||
|
// TODO: update once ComponentReference works with directed event bus.
|
||||||
|
if (!TryComp(pulled, out RotatableComponent? rotatable))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!rotatable.RotateWhilePulling)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var xforms = GetEntityQuery<TransformComponent>();
|
||||||
|
var pulledXform = xforms.GetComponent(pulled);
|
||||||
|
var pullerXform = xforms.GetComponent(puller);
|
||||||
|
|
||||||
|
var pullerData = TransformSystem.GetWorldPositionRotation(pullerXform, xforms);
|
||||||
|
var pulledData = TransformSystem.GetWorldPositionRotation(pulledXform, xforms);
|
||||||
|
|
||||||
|
var dir = pullerData.WorldPosition - pulledData.WorldPosition;
|
||||||
|
if (dir.LengthSquared() > ThresholdRotDistance * ThresholdRotDistance)
|
||||||
|
{
|
||||||
|
var oldAngle = pulledData.WorldRotation;
|
||||||
|
var newAngle = Angle.FromWorldVec(dir);
|
||||||
|
|
||||||
|
var diff = newAngle - oldAngle;
|
||||||
|
if (Math.Abs(diff.Degrees) > ThresholdRotAngle / 2f)
|
||||||
|
{
|
||||||
|
// Ok, so this bit is difficult because ideally it would look like it's snapping to sane angles.
|
||||||
|
// Otherwise PIANO DOOR STUCK! happens.
|
||||||
|
// But it also needs to work with station rotation / align to the local parent.
|
||||||
|
// So...
|
||||||
|
var baseRotation = pulledData.WorldRotation - pulledXform.LocalRotation;
|
||||||
|
var localRotation = newAngle - baseRotation;
|
||||||
|
var localRotationSnapped = Angle.FromDegrees(Math.Floor((localRotation.Degrees / ThresholdRotAngle) + 0.5f) * ThresholdRotAngle);
|
||||||
|
TransformSystem.SetLocalRotation(pulledXform, localRotationSnapped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateBeforeSolve(bool prediction, float frameTime)
|
||||||
|
{
|
||||||
|
base.UpdateBeforeSolve(prediction, frameTime);
|
||||||
|
|
||||||
|
foreach (var pullable in _pullableSystem.Moving)
|
||||||
|
{
|
||||||
|
// There's a 1-frame delay between stopping moving something and it leaving the Moving set.
|
||||||
|
// This can include if leaving the Moving set due to not being pulled anymore,
|
||||||
|
// or due to being deleted.
|
||||||
|
|
||||||
|
if (pullable.Deleted)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pullable.MovingTo == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pullable.Puller is not {Valid: true} puller)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var pullableEnt = pullable.Owner;
|
||||||
|
var pullableXform = Transform(pullableEnt);
|
||||||
|
var pullerXform = Transform(puller);
|
||||||
|
|
||||||
|
// Now that's over with...
|
||||||
|
|
||||||
|
var pullerPosition = pullerXform.MapPosition;
|
||||||
|
var movingTo = pullable.MovingTo.Value.ToMap(EntityManager, _transform);
|
||||||
|
if (movingTo.MapId != pullerPosition.MapId)
|
||||||
|
{
|
||||||
|
_pullableSystem.StopMoveTo(pullable);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryComp<PhysicsComponent>(pullableEnt, out var physics) ||
|
||||||
|
physics.BodyType == BodyType.Static ||
|
||||||
|
movingTo.MapId != pullableXform.MapID)
|
||||||
|
{
|
||||||
|
_pullableSystem.StopMoveTo(pullable);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var movingPosition = movingTo.Position;
|
||||||
|
var ownerPosition = pullableXform.MapPosition.Position;
|
||||||
|
|
||||||
|
var diff = movingPosition - ownerPosition;
|
||||||
|
var diffLength = diff.Length();
|
||||||
|
|
||||||
|
if (diffLength < MaximumSettleDistance && physics.LinearVelocity.Length() < MaximumSettleVelocity)
|
||||||
|
{
|
||||||
|
PhysicsSystem.SetLinearVelocity(pullableEnt, Vector2.Zero, body: physics);
|
||||||
|
_pullableSystem.StopMoveTo(pullable);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var impulseModifierLerp = Math.Min(1.0f, Math.Max(0.0f, (physics.Mass - AccelModifierLowMass) / (AccelModifierHighMass - AccelModifierLowMass)));
|
||||||
|
var impulseModifier = MathHelper.Lerp(AccelModifierLow, AccelModifierHigh, impulseModifierLerp);
|
||||||
|
var multiplier = diffLength < 1 ? impulseModifier * diffLength : impulseModifier;
|
||||||
|
// Note the implication that the real rules of physics don't apply to pulling control.
|
||||||
|
var accel = diff.Normalized() * multiplier;
|
||||||
|
// Now for the part where velocity gets shutdown...
|
||||||
|
if (diffLength < SettleShutdownDistance && physics.LinearVelocity.Length() >= SettleMinimumShutdownVelocity)
|
||||||
|
{
|
||||||
|
// Shutdown velocity increases as we get closer to centre
|
||||||
|
var scaling = (SettleShutdownDistance - diffLength) / SettleShutdownDistance;
|
||||||
|
accel -= physics.LinearVelocity * SettleShutdownMultiplier * scaling;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsSystem.WakeBody(pullableEnt, body: physics);
|
||||||
|
|
||||||
|
var impulse = accel * physics.Mass * frameTime;
|
||||||
|
PhysicsSystem.ApplyLinearImpulse(pullableEnt, impulse, body: physics);
|
||||||
|
|
||||||
|
// if the puller is weightless or can't move, then we apply the inverse impulse (Newton's third law).
|
||||||
|
// doing it under gravity produces an unsatisfying wiggling when pulling.
|
||||||
|
// If player can't move, assume they are on a chair and we need to prevent pull-moving.
|
||||||
|
if ((_gravity.IsWeightless(puller) && pullerXform.GridUid == null) || !_actionBlockerSystem.CanMove(puller))
|
||||||
|
{
|
||||||
|
PhysicsSystem.WakeBody(puller);
|
||||||
|
PhysicsSystem.ApplyLinearImpulse(puller, -impulse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
48
Content.Server/Pulling/PullingSystem.cs
Normal file
48
Content.Server/Pulling/PullingSystem.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using Content.Shared.Input;
|
||||||
|
using Content.Shared.Pulling;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Shared.Input.Binding;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
|
namespace Content.Server.Pulling
|
||||||
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
|
public sealed class PullingSystem : SharedPullingSystem
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
UpdatesAfter.Add(typeof(PhysicsSystem));
|
||||||
|
|
||||||
|
SubscribeLocalEvent<SharedPullableComponent, PullableMoveMessage>(OnPullableMove);
|
||||||
|
SubscribeLocalEvent<SharedPullableComponent, PullableStopMovingMessage>(OnPullableStopMove);
|
||||||
|
|
||||||
|
CommandBinds.Builder
|
||||||
|
.Bind(ContentKeyFunctions.ReleasePulledObject, InputCmdHandler.FromDelegate(HandleReleasePulledObject))
|
||||||
|
.Register<PullingSystem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleReleasePulledObject(ICommonSession? session)
|
||||||
|
{
|
||||||
|
if (session?.AttachedEntity is not {Valid: true} player)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryGetPulled(player, out var pulled))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!EntityManager.TryGetComponent(pulled.Value, out SharedPullableComponent? pullable))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TryStopPull(pullable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;
|
using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Movement.Pulling.Events;
|
using Content.Shared.Physics.Pull;
|
||||||
using Content.Shared.Weapons.Melee.Events;
|
using Content.Shared.Weapons.Melee.Events;
|
||||||
|
|
||||||
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems;
|
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems;
|
||||||
@@ -22,7 +22,7 @@ public sealed class ArtifactInteractionTriggerSystem : EntitySystem
|
|||||||
if (!component.PullActivation)
|
if (!component.PullActivation)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_artifactSystem.TryActivateArtifact(uid, args.PullerUid);
|
_artifactSystem.TryActivateArtifact(uid, args.Puller.Owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAttack(EntityUid uid, ArtifactInteractionTriggerComponent component, AttackedEvent args)
|
private void OnAttack(EntityUid uid, ArtifactInteractionTriggerComponent component, AttackedEvent args)
|
||||||
|
|||||||
@@ -24,12 +24,12 @@ using Content.Shared.Humanoid;
|
|||||||
using Content.Shared.Mobs;
|
using Content.Shared.Mobs;
|
||||||
using Content.Shared.Mobs.Components;
|
using Content.Shared.Mobs.Components;
|
||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
using Content.Shared.Movement.Pulling.Components;
|
|
||||||
using Content.Shared.Movement.Systems;
|
using Content.Shared.Movement.Systems;
|
||||||
using Content.Shared.Nutrition.AnimalHusbandry;
|
using Content.Shared.Nutrition.AnimalHusbandry;
|
||||||
using Content.Shared.Nutrition.Components;
|
using Content.Shared.Nutrition.Components;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
using Content.Shared.Weapons.Melee;
|
using Content.Shared.Weapons.Melee;
|
||||||
using Content.Shared.Zombies;
|
using Content.Shared.Zombies;
|
||||||
using Content.Shared.Prying.Components;
|
using Content.Shared.Prying.Components;
|
||||||
@@ -57,6 +57,7 @@ namespace Content.Server.Zombies
|
|||||||
[Dependency] private readonly IChatManager _chatMan = default!;
|
[Dependency] private readonly IChatManager _chatMan = default!;
|
||||||
[Dependency] private readonly MindSystem _mind = default!;
|
[Dependency] private readonly MindSystem _mind = default!;
|
||||||
[Dependency] private readonly SharedRoleSystem _roles = default!;
|
[Dependency] private readonly SharedRoleSystem _roles = default!;
|
||||||
|
[Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -262,9 +263,7 @@ namespace Content.Server.Zombies
|
|||||||
RemComp(target, handsComp);
|
RemComp(target, handsComp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sloth: What the fuck?
|
RemComp<SharedPullerComponent>(target);
|
||||||
// How long until compregistry lmao.
|
|
||||||
RemComp<PullerComponent>(target);
|
|
||||||
|
|
||||||
// No longer waiting to become a zombie:
|
// No longer waiting to become a zombie:
|
||||||
// Requires deferral because this is (probably) the event which called ZombifyEntity in the first place.
|
// Requires deferral because this is (probably) the event which called ZombifyEntity in the first place.
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
|
using Content.Shared.Movement;
|
||||||
using Content.Shared.Movement.Events;
|
using Content.Shared.Movement.Events;
|
||||||
using Content.Shared.Movement.Pulling.Components;
|
using Content.Shared.Physics.Pull;
|
||||||
using Content.Shared.Movement.Pulling.Events;
|
using Content.Shared.Pulling;
|
||||||
using Content.Shared.Movement.Pulling.Systems;
|
using Content.Shared.Pulling.Components;
|
||||||
|
using Content.Shared.Pulling.Events;
|
||||||
|
using Content.Shared.Stunnable;
|
||||||
using Content.Shared.Throwing;
|
using Content.Shared.Throwing;
|
||||||
|
|
||||||
namespace Content.Shared.Administration;
|
namespace Content.Shared.Administration;
|
||||||
@@ -12,7 +15,7 @@ namespace Content.Shared.Administration;
|
|||||||
public sealed class AdminFrozenSystem : EntitySystem
|
public sealed class AdminFrozenSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
|
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
|
||||||
[Dependency] private readonly PullingSystem _pulling = default!;
|
[Dependency] private readonly SharedPullingSystem _pulling = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -42,9 +45,9 @@ public sealed class AdminFrozenSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnStartup(EntityUid uid, AdminFrozenComponent component, ComponentStartup args)
|
private void OnStartup(EntityUid uid, AdminFrozenComponent component, ComponentStartup args)
|
||||||
{
|
{
|
||||||
if (TryComp<PullableComponent>(uid, out var pullable))
|
if (TryComp<SharedPullableComponent>(uid, out var pullable))
|
||||||
{
|
{
|
||||||
_pulling.TryStopPull(uid, pullable);
|
_pulling.TryStopPull(pullable);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateCanMove(uid, component, args);
|
UpdateCanMove(uid, component, args);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ using Content.Shared.Interaction.Events;
|
|||||||
using Content.Shared.Mobs.Components;
|
using Content.Shared.Mobs.Components;
|
||||||
using Content.Shared.Movement.Events;
|
using Content.Shared.Movement.Events;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
using Content.Shared.Standing;
|
using Content.Shared.Standing;
|
||||||
using Content.Shared.Storage.Components;
|
using Content.Shared.Storage.Components;
|
||||||
using Content.Shared.Stunnable;
|
using Content.Shared.Stunnable;
|
||||||
@@ -19,7 +20,6 @@ using Content.Shared.Verbs;
|
|||||||
using Robust.Shared.Physics.Components;
|
using Robust.Shared.Physics.Components;
|
||||||
using Robust.Shared.Physics.Events;
|
using Robust.Shared.Physics.Events;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using PullableComponent = Content.Shared.Movement.Pulling.Components.PullableComponent;
|
|
||||||
|
|
||||||
namespace Content.Shared.Buckle;
|
namespace Content.Shared.Buckle;
|
||||||
|
|
||||||
@@ -356,11 +356,11 @@ public abstract partial class SharedBuckleSystem
|
|||||||
RaiseLocalEvent(ev.BuckledEntity, ref ev);
|
RaiseLocalEvent(ev.BuckledEntity, ref ev);
|
||||||
RaiseLocalEvent(ev.StrapEntity, ref ev);
|
RaiseLocalEvent(ev.StrapEntity, ref ev);
|
||||||
|
|
||||||
if (TryComp<PullableComponent>(buckleUid, out var ownerPullable))
|
if (TryComp<SharedPullableComponent>(buckleUid, out var ownerPullable))
|
||||||
{
|
{
|
||||||
if (ownerPullable.Puller != null)
|
if (ownerPullable.Puller != null)
|
||||||
{
|
{
|
||||||
_pulling.TryStopPull(buckleUid, ownerPullable);
|
_pulling.TryStopPull(ownerPullable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,12 +369,12 @@ public abstract partial class SharedBuckleSystem
|
|||||||
_physics.ResetDynamics(physics);
|
_physics.ResetDynamics(physics);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!buckleComp.PullStrap && TryComp<PullableComponent>(strapUid, out var toPullable))
|
if (!buckleComp.PullStrap && TryComp<SharedPullableComponent>(strapUid, out var toPullable))
|
||||||
{
|
{
|
||||||
if (toPullable.Puller == buckleUid)
|
if (toPullable.Puller == buckleUid)
|
||||||
{
|
{
|
||||||
// can't pull it and buckle to it at the same time
|
// can't pull it and buckle to it at the same time
|
||||||
_pulling.TryStopPull(strapUid, toPullable);
|
_pulling.TryStopPull(toPullable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ using Robust.Shared.Network;
|
|||||||
using Robust.Shared.Physics.Systems;
|
using Robust.Shared.Physics.Systems;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using PullingSystem = Content.Shared.Movement.Pulling.Systems.PullingSystem;
|
|
||||||
|
|
||||||
namespace Content.Shared.Buckle;
|
namespace Content.Shared.Buckle;
|
||||||
|
|
||||||
@@ -36,7 +35,7 @@ public abstract partial class SharedBuckleSystem : EntitySystem
|
|||||||
[Dependency] private readonly SharedInteractionSystem _interaction = default!;
|
[Dependency] private readonly SharedInteractionSystem _interaction = default!;
|
||||||
[Dependency] private readonly SharedJointSystem _joints = default!;
|
[Dependency] private readonly SharedJointSystem _joints = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
[Dependency] private readonly PullingSystem _pulling = default!;
|
[Dependency] private readonly SharedPullingSystem _pulling = default!;
|
||||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
[Dependency] private readonly StandingStateSystem _standing = default!;
|
[Dependency] private readonly StandingStateSystem _standing = default!;
|
||||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||||
|
|||||||
@@ -6,15 +6,16 @@ using Content.Shared.Coordinates.Helpers;
|
|||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Movement.Pulling.Components;
|
|
||||||
using Content.Shared.Movement.Pulling.Systems;
|
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Pulling;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
using Content.Shared.Tools;
|
using Content.Shared.Tools;
|
||||||
using Content.Shared.Tools.Components;
|
using Content.Shared.Tools.Components;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Map.Components;
|
using Robust.Shared.Map.Components;
|
||||||
using Robust.Shared.Physics.Components;
|
using Robust.Shared.Physics.Components;
|
||||||
using Content.Shared.Tag;
|
using Content.Shared.Tag;
|
||||||
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem;
|
using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem;
|
||||||
@@ -26,7 +27,7 @@ public sealed partial class AnchorableSystem : EntitySystem
|
|||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
[Dependency] private readonly PullingSystem _pulling = default!;
|
[Dependency] private readonly SharedPullingSystem _pulling = default!;
|
||||||
[Dependency] private readonly SharedToolSystem _tool = default!;
|
[Dependency] private readonly SharedToolSystem _tool = default!;
|
||||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||||
@@ -128,9 +129,9 @@ public sealed partial class AnchorableSystem : EntitySystem
|
|||||||
var rot = xform.LocalRotation;
|
var rot = xform.LocalRotation;
|
||||||
xform.LocalRotation = Math.Round(rot / (Math.PI / 2)) * (Math.PI / 2);
|
xform.LocalRotation = Math.Round(rot / (Math.PI / 2)) * (Math.PI / 2);
|
||||||
|
|
||||||
if (TryComp<PullableComponent>(uid, out var pullable) && pullable.Puller != null)
|
if (TryComp<SharedPullableComponent>(uid, out var pullable) && pullable.Puller != null)
|
||||||
{
|
{
|
||||||
_pulling.TryStopPull(uid, pullable);
|
_pulling.TryStopPull(pullable);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Anchoring snaps rn anyway!
|
// TODO: Anchoring snaps rn anyway!
|
||||||
@@ -171,7 +172,7 @@ public sealed partial class AnchorableSystem : EntitySystem
|
|||||||
public void TryToggleAnchor(EntityUid uid, EntityUid userUid, EntityUid usingUid,
|
public void TryToggleAnchor(EntityUid uid, EntityUid userUid, EntityUid usingUid,
|
||||||
AnchorableComponent? anchorable = null,
|
AnchorableComponent? anchorable = null,
|
||||||
TransformComponent? transform = null,
|
TransformComponent? transform = null,
|
||||||
PullableComponent? pullable = null,
|
SharedPullableComponent? pullable = null,
|
||||||
ToolComponent? usingTool = null)
|
ToolComponent? usingTool = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref transform))
|
if (!Resolve(uid, ref transform))
|
||||||
@@ -200,7 +201,7 @@ public sealed partial class AnchorableSystem : EntitySystem
|
|||||||
private void TryAnchor(EntityUid uid, EntityUid userUid, EntityUid usingUid,
|
private void TryAnchor(EntityUid uid, EntityUid userUid, EntityUid usingUid,
|
||||||
AnchorableComponent? anchorable = null,
|
AnchorableComponent? anchorable = null,
|
||||||
TransformComponent? transform = null,
|
TransformComponent? transform = null,
|
||||||
PullableComponent? pullable = null,
|
SharedPullableComponent? pullable = null,
|
||||||
ToolComponent? usingTool = null)
|
ToolComponent? usingTool = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref anchorable, ref transform))
|
if (!Resolve(uid, ref anchorable, ref transform))
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ using Content.Shared.Inventory.VirtualItem;
|
|||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
using Content.Shared.Movement.Events;
|
using Content.Shared.Movement.Events;
|
||||||
using Content.Shared.Movement.Pulling.Events;
|
using Content.Shared.Physics.Pull;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
using Content.Shared.Pulling.Events;
|
using Content.Shared.Pulling.Events;
|
||||||
using Content.Shared.Rejuvenate;
|
using Content.Shared.Rejuvenate;
|
||||||
using Content.Shared.Stunnable;
|
using Content.Shared.Stunnable;
|
||||||
@@ -35,7 +36,6 @@ using Robust.Shared.Containers;
|
|||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using PullableComponent = Content.Shared.Movement.Pulling.Components.PullableComponent;
|
|
||||||
|
|
||||||
namespace Content.Shared.Cuffs
|
namespace Content.Shared.Cuffs
|
||||||
{
|
{
|
||||||
@@ -70,7 +70,7 @@ namespace Content.Shared.Cuffs
|
|||||||
SubscribeLocalEvent<CuffableComponent, EntInsertedIntoContainerMessage>(OnCuffsInsertedIntoContainer);
|
SubscribeLocalEvent<CuffableComponent, EntInsertedIntoContainerMessage>(OnCuffsInsertedIntoContainer);
|
||||||
SubscribeLocalEvent<CuffableComponent, RejuvenateEvent>(OnRejuvenate);
|
SubscribeLocalEvent<CuffableComponent, RejuvenateEvent>(OnRejuvenate);
|
||||||
SubscribeLocalEvent<CuffableComponent, ComponentInit>(OnStartup);
|
SubscribeLocalEvent<CuffableComponent, ComponentInit>(OnStartup);
|
||||||
SubscribeLocalEvent<CuffableComponent, AttemptStopPullingEvent>(HandleStopPull);
|
SubscribeLocalEvent<CuffableComponent, StopPullingEvent>(HandleStopPull);
|
||||||
SubscribeLocalEvent<CuffableComponent, UpdateCanMoveEvent>(HandleMoveAttempt);
|
SubscribeLocalEvent<CuffableComponent, UpdateCanMoveEvent>(HandleMoveAttempt);
|
||||||
SubscribeLocalEvent<CuffableComponent, IsEquippingAttemptEvent>(OnEquipAttempt);
|
SubscribeLocalEvent<CuffableComponent, IsEquippingAttemptEvent>(OnEquipAttempt);
|
||||||
SubscribeLocalEvent<CuffableComponent, IsUnequippingAttemptEvent>(OnUnequipAttempt);
|
SubscribeLocalEvent<CuffableComponent, IsUnequippingAttemptEvent>(OnUnequipAttempt);
|
||||||
@@ -182,7 +182,7 @@ namespace Content.Shared.Cuffs
|
|||||||
|
|
||||||
private void OnBeingPulledAttempt(EntityUid uid, CuffableComponent component, BeingPulledAttemptEvent args)
|
private void OnBeingPulledAttempt(EntityUid uid, CuffableComponent component, BeingPulledAttemptEvent args)
|
||||||
{
|
{
|
||||||
if (!TryComp<PullableComponent>(uid, out var pullable))
|
if (!TryComp<SharedPullableComponent>(uid, out var pullable))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (pullable.Puller != null && !component.CanStillInteract) // If we are being pulled already and cuffed, we can't get pulled again.
|
if (pullable.Puller != null && !component.CanStillInteract) // If we are being pulled already and cuffed, we can't get pulled again.
|
||||||
@@ -214,19 +214,19 @@ namespace Content.Shared.Cuffs
|
|||||||
|
|
||||||
private void HandleMoveAttempt(EntityUid uid, CuffableComponent component, UpdateCanMoveEvent args)
|
private void HandleMoveAttempt(EntityUid uid, CuffableComponent component, UpdateCanMoveEvent args)
|
||||||
{
|
{
|
||||||
if (component.CanStillInteract || !EntityManager.TryGetComponent(uid, out PullableComponent? pullable) || !pullable.BeingPulled)
|
if (component.CanStillInteract || !EntityManager.TryGetComponent(uid, out SharedPullableComponent? pullable) || !pullable.BeingPulled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
args.Cancel();
|
args.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleStopPull(EntityUid uid, CuffableComponent component, AttemptStopPullingEvent args)
|
private void HandleStopPull(EntityUid uid, CuffableComponent component, StopPullingEvent args)
|
||||||
{
|
{
|
||||||
if (args.User == null || !Exists(args.User.Value))
|
if (args.User == null || !Exists(args.User.Value))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (args.User.Value == uid && !component.CanStillInteract)
|
if (args.User.Value == uid && !component.CanStillInteract)
|
||||||
args.Cancelled = true;
|
args.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddUncuffVerb(EntityUid uid, CuffableComponent component, GetVerbsEvent<Verb> args)
|
private void AddUncuffVerb(EntityUid uid, CuffableComponent component, GetVerbsEvent<Verb> args)
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ using Content.Shared.Follower.Components;
|
|||||||
using Content.Shared.Ghost;
|
using Content.Shared.Ghost;
|
||||||
using Content.Shared.Hands;
|
using Content.Shared.Hands;
|
||||||
using Content.Shared.Movement.Events;
|
using Content.Shared.Movement.Events;
|
||||||
using Content.Shared.Movement.Pulling.Events;
|
|
||||||
using Content.Shared.Movement.Systems;
|
using Content.Shared.Movement.Systems;
|
||||||
|
using Content.Shared.Physics.Pull;
|
||||||
using Content.Shared.Tag;
|
using Content.Shared.Tag;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ using System.Numerics;
|
|||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.Gravity;
|
using Content.Shared.Gravity;
|
||||||
using Content.Shared.Movement.Events;
|
using Content.Shared.Movement.Events;
|
||||||
using Content.Shared.Movement.Pulling.Components;
|
|
||||||
using Content.Shared.Movement.Systems;
|
using Content.Shared.Movement.Systems;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
@@ -23,12 +23,6 @@ namespace Content.Shared.Friction
|
|||||||
[Dependency] private readonly SharedMoverController _mover = default!;
|
[Dependency] private readonly SharedMoverController _mover = default!;
|
||||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||||
|
|
||||||
private EntityQuery<TileFrictionModifierComponent> _frictionQuery;
|
|
||||||
private EntityQuery<TransformComponent> _xformQuery;
|
|
||||||
private EntityQuery<PullerComponent> _pullerQuery;
|
|
||||||
private EntityQuery<PullableComponent> _pullableQuery;
|
|
||||||
private EntityQuery<MapGridComponent> _gridQuery;
|
|
||||||
|
|
||||||
private float _stopSpeed;
|
private float _stopSpeed;
|
||||||
private float _frictionModifier;
|
private float _frictionModifier;
|
||||||
public const float DefaultFriction = 0.3f;
|
public const float DefaultFriction = 0.3f;
|
||||||
@@ -37,12 +31,6 @@ namespace Content.Shared.Friction
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
_frictionQuery = GetEntityQuery<TileFrictionModifierComponent>();
|
|
||||||
_xformQuery = GetEntityQuery<TransformComponent>();
|
|
||||||
_pullerQuery = GetEntityQuery<PullerComponent>();
|
|
||||||
_pullableQuery = GetEntityQuery<PullableComponent>();
|
|
||||||
_gridQuery = GetEntityQuery<MapGridComponent>();
|
|
||||||
|
|
||||||
_configManager.OnValueChanged(CCVars.TileFrictionModifier, SetFrictionModifier, true);
|
_configManager.OnValueChanged(CCVars.TileFrictionModifier, SetFrictionModifier, true);
|
||||||
_configManager.OnValueChanged(CCVars.StopSpeed, SetStopSpeed, true);
|
_configManager.OnValueChanged(CCVars.StopSpeed, SetStopSpeed, true);
|
||||||
}
|
}
|
||||||
@@ -63,6 +51,12 @@ namespace Content.Shared.Friction
|
|||||||
{
|
{
|
||||||
base.UpdateBeforeMapSolve(prediction, mapComponent, frameTime);
|
base.UpdateBeforeMapSolve(prediction, mapComponent, frameTime);
|
||||||
|
|
||||||
|
var frictionQuery = GetEntityQuery<TileFrictionModifierComponent>();
|
||||||
|
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||||
|
var pullerQuery = GetEntityQuery<SharedPullerComponent>();
|
||||||
|
var pullableQuery = GetEntityQuery<SharedPullableComponent>();
|
||||||
|
var gridQuery = GetEntityQuery<MapGridComponent>();
|
||||||
|
|
||||||
foreach (var body in mapComponent.AwakeBodies)
|
foreach (var body in mapComponent.AwakeBodies)
|
||||||
{
|
{
|
||||||
var uid = body.Owner;
|
var uid = body.Owner;
|
||||||
@@ -78,16 +72,16 @@ namespace Content.Shared.Friction
|
|||||||
if (body.LinearVelocity.Equals(Vector2.Zero) && body.AngularVelocity.Equals(0f))
|
if (body.LinearVelocity.Equals(Vector2.Zero) && body.AngularVelocity.Equals(0f))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!_xformQuery.TryGetComponent(uid, out var xform))
|
if (!xformQuery.TryGetComponent(uid, out var xform))
|
||||||
{
|
{
|
||||||
Log.Error($"Unable to get transform for {ToPrettyString(uid)} in tilefrictioncontroller");
|
Log.Error($"Unable to get transform for {ToPrettyString(uid)} in tilefrictioncontroller");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var surfaceFriction = GetTileFriction(uid, body, xform);
|
var surfaceFriction = GetTileFriction(uid, body, xform, gridQuery, frictionQuery);
|
||||||
var bodyModifier = 1f;
|
var bodyModifier = 1f;
|
||||||
|
|
||||||
if (_frictionQuery.TryGetComponent(uid, out var frictionComp))
|
if (frictionQuery.TryGetComponent(uid, out var frictionComp))
|
||||||
{
|
{
|
||||||
bodyModifier = frictionComp.Modifier;
|
bodyModifier = frictionComp.Modifier;
|
||||||
}
|
}
|
||||||
@@ -100,8 +94,8 @@ namespace Content.Shared.Friction
|
|||||||
// If we're sandwiched between 2 pullers reduce friction
|
// If we're sandwiched between 2 pullers reduce friction
|
||||||
// Might be better to make this dynamic and check how many are in the pull chain?
|
// Might be better to make this dynamic and check how many are in the pull chain?
|
||||||
// Either way should be much faster for now.
|
// Either way should be much faster for now.
|
||||||
if (_pullerQuery.TryGetComponent(uid, out var puller) && puller.Pulling != null &&
|
if (pullerQuery.TryGetComponent(uid, out var puller) && puller.Pulling != null &&
|
||||||
_pullableQuery.TryGetComponent(uid, out var pullable) && pullable.BeingPulled)
|
pullableQuery.TryGetComponent(uid, out var pullable) && pullable.BeingPulled)
|
||||||
{
|
{
|
||||||
bodyModifier *= 0.2f;
|
bodyModifier *= 0.2f;
|
||||||
}
|
}
|
||||||
@@ -181,7 +175,9 @@ namespace Content.Shared.Friction
|
|||||||
private float GetTileFriction(
|
private float GetTileFriction(
|
||||||
EntityUid uid,
|
EntityUid uid,
|
||||||
PhysicsComponent body,
|
PhysicsComponent body,
|
||||||
TransformComponent xform)
|
TransformComponent xform,
|
||||||
|
EntityQuery<MapGridComponent> gridQuery,
|
||||||
|
EntityQuery<TileFrictionModifierComponent> frictionQuery)
|
||||||
{
|
{
|
||||||
// TODO: Make IsWeightless event-based; we already have grid traversals tracked so just raise events
|
// TODO: Make IsWeightless event-based; we already have grid traversals tracked so just raise events
|
||||||
if (_gravity.IsWeightless(uid, body, xform))
|
if (_gravity.IsWeightless(uid, body, xform))
|
||||||
@@ -191,9 +187,9 @@ namespace Content.Shared.Friction
|
|||||||
return 0.0f;
|
return 0.0f;
|
||||||
|
|
||||||
// If not on a grid then return the map's friction.
|
// If not on a grid then return the map's friction.
|
||||||
if (!_gridQuery.TryGetComponent(xform.GridUid, out var grid))
|
if (!gridQuery.TryGetComponent(xform.GridUid, out var grid))
|
||||||
{
|
{
|
||||||
return _frictionQuery.TryGetComponent(xform.MapUid, out var friction)
|
return frictionQuery.TryGetComponent(xform.MapUid, out var friction)
|
||||||
? friction.Modifier
|
? friction.Modifier
|
||||||
: DefaultFriction;
|
: DefaultFriction;
|
||||||
}
|
}
|
||||||
@@ -213,7 +209,7 @@ namespace Content.Shared.Friction
|
|||||||
|
|
||||||
while (anc.MoveNext(out var tileEnt))
|
while (anc.MoveNext(out var tileEnt))
|
||||||
{
|
{
|
||||||
if (_frictionQuery.TryGetComponent(tileEnt, out var friction))
|
if (frictionQuery.TryGetComponent(tileEnt, out var friction))
|
||||||
return friction.Modifier;
|
return friction.Modifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ using Content.Shared.Inventory;
|
|||||||
using Content.Shared.Inventory.Events;
|
using Content.Shared.Inventory.Events;
|
||||||
using Content.Shared.Item;
|
using Content.Shared.Item;
|
||||||
using Content.Shared.Movement.Components;
|
using Content.Shared.Movement.Components;
|
||||||
using Content.Shared.Movement.Pulling.Components;
|
|
||||||
using Content.Shared.Movement.Pulling.Systems;
|
|
||||||
using Content.Shared.Physics;
|
using Content.Shared.Physics;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Pulling;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
using Content.Shared.Tag;
|
using Content.Shared.Tag;
|
||||||
using Content.Shared.Timing;
|
using Content.Shared.Timing;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
@@ -60,7 +60,7 @@ namespace Content.Shared.Interaction
|
|||||||
[Dependency] private readonly SharedVerbSystem _verbSystem = default!;
|
[Dependency] private readonly SharedVerbSystem _verbSystem = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||||
[Dependency] private readonly UseDelaySystem _useDelay = default!;
|
[Dependency] private readonly UseDelaySystem _useDelay = default!;
|
||||||
[Dependency] private readonly PullingSystem _pullSystem = default!;
|
[Dependency] private readonly SharedPullingSystem _pullSystem = default!;
|
||||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly TagSystem _tagSystem = default!;
|
[Dependency] private readonly TagSystem _tagSystem = default!;
|
||||||
@@ -185,10 +185,10 @@ namespace Content.Shared.Interaction
|
|||||||
if (!InRangeUnobstructed(userEntity.Value, uid, popup: true))
|
if (!InRangeUnobstructed(userEntity.Value, uid, popup: true))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!TryComp(uid, out PullableComponent? pull))
|
if (!TryComp(uid, out SharedPullableComponent? pull))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_pullSystem.TogglePull(uid, userEntity.Value, pull);
|
_pullSystem.TogglePull(userEntity.Value, pull);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
using Robust.Shared.GameStates;
|
|
||||||
|
|
||||||
namespace Content.Shared.Movement.Pulling.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Specifies an entity as being pullable by an entity with <see cref="PullerComponent"/>
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
|
||||||
[Access(typeof(Systems.PullingSystem))]
|
|
||||||
public sealed partial class PullableComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The current entity pulling this component.
|
|
||||||
/// </summary>
|
|
||||||
[AutoNetworkedField, DataField]
|
|
||||||
public EntityUid? Puller;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The pull joint.
|
|
||||||
/// </summary>
|
|
||||||
[AutoNetworkedField, DataField]
|
|
||||||
public string? PullJointId;
|
|
||||||
|
|
||||||
public bool BeingPulled => Puller != null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// If the physics component has FixedRotation should we keep it upon being pulled
|
|
||||||
/// </summary>
|
|
||||||
[Access(typeof(Systems.PullingSystem), Other = AccessPermissions.ReadExecute)]
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("fixedRotation")]
|
|
||||||
public bool FixedRotationOnPull;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// What the pullable's fixedrotation was set to before being pulled.
|
|
||||||
/// </summary>
|
|
||||||
[Access(typeof(Systems.PullingSystem), Other = AccessPermissions.ReadExecute)]
|
|
||||||
[AutoNetworkedField, DataField]
|
|
||||||
public bool PrevFixedRotation;
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
using Content.Shared.Movement.Pulling.Systems;
|
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
|
||||||
|
|
||||||
namespace Content.Shared.Movement.Pulling.Components;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Specifies an entity as being able to pull another entity with <see cref="PullableComponent"/>
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
|
||||||
[Access(typeof(PullingSystem))]
|
|
||||||
public sealed partial class PullerComponent : Component
|
|
||||||
{
|
|
||||||
// My raiding guild
|
|
||||||
/// <summary>
|
|
||||||
/// Next time the puller can throw what is being pulled.
|
|
||||||
/// Used to avoid spamming it for infinite spin + velocity.
|
|
||||||
/// </summary>
|
|
||||||
[DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField]
|
|
||||||
public TimeSpan NextThrow;
|
|
||||||
|
|
||||||
[DataField]
|
|
||||||
public TimeSpan ThrowCooldown = TimeSpan.FromSeconds(1);
|
|
||||||
|
|
||||||
// Before changing how this is updated, please see SharedPullerSystem.RefreshMovementSpeed
|
|
||||||
public float WalkSpeedModifier => Pulling == default ? 1.0f : 0.95f;
|
|
||||||
|
|
||||||
public float SprintSpeedModifier => Pulling == default ? 1.0f : 0.95f;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Entity currently being pulled if applicable.
|
|
||||||
/// </summary>
|
|
||||||
[AutoNetworkedField, DataField]
|
|
||||||
public EntityUid? Pulling;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Does this entity need hands to be able to pull something?
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public bool NeedsHands = true;
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using Robust.Shared.Physics.Components;
|
|
||||||
|
|
||||||
namespace Content.Shared.Movement.Pulling.Events;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raised directed on puller and pullable to determine if it can be pulled.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class PullAttemptEvent : PullMessage
|
|
||||||
{
|
|
||||||
public PullAttemptEvent(EntityUid pullerUid, EntityUid pullableUid) : base(pullerUid, pullableUid) { }
|
|
||||||
|
|
||||||
public bool Cancelled { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
namespace Content.Shared.Pulling.Events;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raised when a request is made to stop pulling an entity.
|
|
||||||
/// </summary>
|
|
||||||
public record struct AttemptStopPullingEvent(EntityUid? User = null)
|
|
||||||
{
|
|
||||||
public readonly EntityUid? User = User;
|
|
||||||
public bool Cancelled;
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
namespace Content.Shared.Movement.Pulling.Events;
|
|
||||||
|
|
||||||
public abstract class PullMessage : EntityEventArgs
|
|
||||||
{
|
|
||||||
public readonly EntityUid PullerUid;
|
|
||||||
public readonly EntityUid PulledUid;
|
|
||||||
|
|
||||||
protected PullMessage(EntityUid pullerUid, EntityUid pulledUid)
|
|
||||||
{
|
|
||||||
PullerUid = pullerUid;
|
|
||||||
PulledUid = pulledUid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace Content.Shared.Movement.Pulling.Events;
|
|
||||||
|
|
||||||
public sealed class PullStartedMessage : PullMessage
|
|
||||||
{
|
|
||||||
public PullStartedMessage(EntityUid pullerUid, EntityUid pullableUid) :
|
|
||||||
base(pullerUid, pullableUid)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using Robust.Shared.Physics.Components;
|
|
||||||
|
|
||||||
namespace Content.Shared.Movement.Pulling.Events;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raised directed on both puller and pullable.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class PullStoppedMessage : PullMessage
|
|
||||||
{
|
|
||||||
public PullStoppedMessage(EntityUid pullerUid, EntityUid pulledUid) : base(pullerUid, pulledUid)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,455 +0,0 @@
|
|||||||
using System.Numerics;
|
|
||||||
using Content.Shared.ActionBlocker;
|
|
||||||
using Content.Shared.Administration.Logs;
|
|
||||||
using Content.Shared.Alert;
|
|
||||||
using Content.Shared.Buckle.Components;
|
|
||||||
using Content.Shared.Database;
|
|
||||||
using Content.Shared.Hands;
|
|
||||||
using Content.Shared.Hands.EntitySystems;
|
|
||||||
using Content.Shared.Input;
|
|
||||||
using Content.Shared.Interaction;
|
|
||||||
using Content.Shared.Movement.Events;
|
|
||||||
using Content.Shared.Movement.Pulling.Components;
|
|
||||||
using Content.Shared.Movement.Pulling.Events;
|
|
||||||
using Content.Shared.Movement.Systems;
|
|
||||||
using Content.Shared.Pulling.Events;
|
|
||||||
using Content.Shared.Throwing;
|
|
||||||
using Content.Shared.Verbs;
|
|
||||||
using Robust.Shared.Containers;
|
|
||||||
using Robust.Shared.Input.Binding;
|
|
||||||
using Robust.Shared.Map;
|
|
||||||
using Robust.Shared.Physics;
|
|
||||||
using Robust.Shared.Physics.Components;
|
|
||||||
using Robust.Shared.Physics.Events;
|
|
||||||
using Robust.Shared.Physics.Systems;
|
|
||||||
using Robust.Shared.Player;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
|
|
||||||
namespace Content.Shared.Movement.Pulling.Systems;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Allows one entity to pull another behind them via a physics distance joint.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class PullingSystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
|
||||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
|
||||||
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
|
|
||||||
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
|
||||||
[Dependency] private readonly MovementSpeedModifierSystem _modifierSystem = default!;
|
|
||||||
[Dependency] private readonly SharedJointSystem _joints = default!;
|
|
||||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
|
||||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
|
||||||
[Dependency] private readonly SharedInteractionSystem _interaction = default!;
|
|
||||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
|
||||||
[Dependency] private readonly SharedTransformSystem _xformSys = default!;
|
|
||||||
[Dependency] private readonly ThrowingSystem _throwing = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
UpdatesAfter.Add(typeof(SharedPhysicsSystem));
|
|
||||||
UpdatesOutsidePrediction = true;
|
|
||||||
|
|
||||||
SubscribeLocalEvent<PullableComponent, MoveInputEvent>(OnPullableMoveInput);
|
|
||||||
SubscribeLocalEvent<PullableComponent, CollisionChangeEvent>(OnPullableCollisionChange);
|
|
||||||
SubscribeLocalEvent<PullableComponent, JointRemovedEvent>(OnJointRemoved);
|
|
||||||
SubscribeLocalEvent<PullableComponent, GetVerbsEvent<Verb>>(AddPullVerbs);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<PullerComponent, EntityUnpausedEvent>(OnPullerUnpaused);
|
|
||||||
SubscribeLocalEvent<PullerComponent, VirtualItemDeletedEvent>(OnVirtualItemDeleted);
|
|
||||||
SubscribeLocalEvent<PullerComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
|
|
||||||
|
|
||||||
CommandBinds.Builder
|
|
||||||
.Bind(ContentKeyFunctions.MovePulledObject, new PointerInputCmdHandler(OnRequestMovePulledObject))
|
|
||||||
.Bind(ContentKeyFunctions.ReleasePulledObject, InputCmdHandler.FromDelegate(OnReleasePulledObject))
|
|
||||||
.Register<PullingSystem>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Shutdown()
|
|
||||||
{
|
|
||||||
base.Shutdown();
|
|
||||||
CommandBinds.Unregister<PullingSystem>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPullerUnpaused(EntityUid uid, PullerComponent component, ref EntityUnpausedEvent args)
|
|
||||||
{
|
|
||||||
component.NextThrow += args.PausedTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnVirtualItemDeleted(EntityUid uid, PullerComponent component, VirtualItemDeletedEvent args)
|
|
||||||
{
|
|
||||||
// If client deletes the virtual hand then stop the pull.
|
|
||||||
if (component.Pulling == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (component.Pulling != args.BlockingEntity)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (EntityManager.TryGetComponent(args.BlockingEntity, out PullableComponent? comp))
|
|
||||||
{
|
|
||||||
TryStopPull(args.BlockingEntity, comp, uid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddPullVerbs(EntityUid uid, PullableComponent component, GetVerbsEvent<Verb> args)
|
|
||||||
{
|
|
||||||
if (!args.CanAccess || !args.CanInteract)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Are they trying to pull themselves up by their bootstraps?
|
|
||||||
if (args.User == args.Target)
|
|
||||||
return;
|
|
||||||
|
|
||||||
//TODO VERB ICONS add pulling icon
|
|
||||||
if (component.Puller == args.User)
|
|
||||||
{
|
|
||||||
Verb verb = new()
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("pulling-verb-get-data-text-stop-pulling"),
|
|
||||||
Act = () => TryStopPull(uid, component, user: args.User),
|
|
||||||
DoContactInteraction = false // pulling handle its own contact interaction.
|
|
||||||
};
|
|
||||||
args.Verbs.Add(verb);
|
|
||||||
}
|
|
||||||
else if (CanPull(args.User, args.Target))
|
|
||||||
{
|
|
||||||
Verb verb = new()
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("pulling-verb-get-data-text"),
|
|
||||||
Act = () => TryStartPull(args.User, args.Target),
|
|
||||||
DoContactInteraction = false // pulling handle its own contact interaction.
|
|
||||||
};
|
|
||||||
args.Verbs.Add(verb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnRefreshMovespeed(EntityUid uid, PullerComponent component, RefreshMovementSpeedModifiersEvent args)
|
|
||||||
{
|
|
||||||
args.ModifySpeed(component.WalkSpeedModifier, component.SprintSpeedModifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPullableMoveInput(EntityUid uid, PullableComponent component, ref MoveInputEvent args)
|
|
||||||
{
|
|
||||||
// If someone moves then break their pulling.
|
|
||||||
if (!component.BeingPulled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var entity = args.Entity;
|
|
||||||
|
|
||||||
if (!_blocker.CanMove(entity))
|
|
||||||
return;
|
|
||||||
|
|
||||||
TryStopPull(uid, component, user: uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPullableCollisionChange(EntityUid uid, PullableComponent component, ref CollisionChangeEvent args)
|
|
||||||
{
|
|
||||||
// IDK what this is supposed to be.
|
|
||||||
if (!_timing.ApplyingState && component.PullJointId != null && !args.CanCollide)
|
|
||||||
{
|
|
||||||
_joints.RemoveJoint(uid, component.PullJointId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnJointRemoved(EntityUid uid, PullableComponent component, JointRemovedEvent args)
|
|
||||||
{
|
|
||||||
// Not relevant / pullable state handle it.
|
|
||||||
if (component.Puller != args.OtherEntity ||
|
|
||||||
args.Joint.ID != component.PullJointId ||
|
|
||||||
_timing.ApplyingState)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args.Joint.ID != component.PullJointId)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CleanupPulling(uid, component);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CleanupPulling(EntityUid pullableUid, PullableComponent pullableComp)
|
|
||||||
{
|
|
||||||
// No more joints with puller -> force stop pull.
|
|
||||||
if (TryComp<PullerComponent>(pullableComp.Puller, out var pullerComp))
|
|
||||||
{
|
|
||||||
pullerComp.Pulling = null;
|
|
||||||
Dirty(pullableComp.Puller.Value, pullerComp);
|
|
||||||
}
|
|
||||||
|
|
||||||
pullableComp.PullJointId = null;
|
|
||||||
pullableComp.Puller = null;
|
|
||||||
Dirty(pullableUid, pullableComp);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsPulled(EntityUid uid, PullableComponent? component = null)
|
|
||||||
{
|
|
||||||
return Resolve(uid, ref component, false) && component.BeingPulled;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool OnRequestMovePulledObject(ICommonSession? session, EntityCoordinates coords, EntityUid uid)
|
|
||||||
{
|
|
||||||
if (session?.AttachedEntity is not { } player ||
|
|
||||||
!player.IsValid())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TryComp<PullerComponent>(player, out var pullerComp))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var pulled = pullerComp.Pulling;
|
|
||||||
|
|
||||||
if (!HasComp<PullableComponent>(pulled))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (_containerSystem.IsEntityInContainer(player))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Cooldown buddy
|
|
||||||
if (_timing.CurTime < pullerComp.NextThrow)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
pullerComp.NextThrow = _timing.CurTime + pullerComp.ThrowCooldown;
|
|
||||||
|
|
||||||
// Cap the distance
|
|
||||||
const float range = 2f;
|
|
||||||
var fromUserCoords = coords.WithEntityId(player, EntityManager);
|
|
||||||
var userCoords = new EntityCoordinates(player, Vector2.Zero);
|
|
||||||
|
|
||||||
if (!userCoords.InRange(EntityManager, _xformSys, fromUserCoords, range))
|
|
||||||
{
|
|
||||||
var userDirection = fromUserCoords.Position - userCoords.Position;
|
|
||||||
fromUserCoords = userCoords.Offset(userDirection.Normalized() * range);
|
|
||||||
}
|
|
||||||
|
|
||||||
Dirty(player, pullerComp);
|
|
||||||
_throwing.TryThrow(pulled.Value, fromUserCoords, user: player, strength: 4f, animated: false, recoil: false, playSound: false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsPulling(EntityUid puller, PullerComponent? component = null)
|
|
||||||
{
|
|
||||||
return Resolve(puller, ref component, false) && component.Pulling != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnReleasePulledObject(ICommonSession? session)
|
|
||||||
{
|
|
||||||
if (session?.AttachedEntity is not {Valid: true} player)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TryComp(player, out PullerComponent? pullerComp) ||
|
|
||||||
!TryComp(pullerComp.Pulling, out PullableComponent? pullableComp))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TryStopPull(pullerComp.Pulling.Value, pullableComp, user: player);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanPull(EntityUid puller, EntityUid pullableUid, PullerComponent? pullerComp = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(puller, ref pullerComp, false))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pullerComp.NeedsHands && !_handsSystem.TryGetEmptyHand(puller, out _))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_blocker.CanInteract(puller, pullableUid))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!EntityManager.TryGetComponent<PhysicsComponent>(pullableUid, out var physics))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (physics.BodyType == BodyType.Static)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (puller == pullableUid)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_containerSystem.IsInSameOrNoContainer(puller, pullableUid))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EntityManager.TryGetComponent(puller, out BuckleComponent? buckle))
|
|
||||||
{
|
|
||||||
// Prevent people pulling the chair they're on, etc.
|
|
||||||
if (buckle is { PullStrap: false, Buckled: true } && (buckle.LastEntityBuckledTo == pullableUid))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var getPulled = new BeingPulledAttemptEvent(puller, pullableUid);
|
|
||||||
RaiseLocalEvent(pullableUid, getPulled, true);
|
|
||||||
var startPull = new StartPullAttemptEvent(puller, pullableUid);
|
|
||||||
RaiseLocalEvent(puller, startPull, true);
|
|
||||||
return !startPull.Cancelled && !getPulled.Cancelled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TogglePull(EntityUid pullableUid, EntityUid pullerUid, PullableComponent pullable)
|
|
||||||
{
|
|
||||||
if (pullable.Puller == pullerUid)
|
|
||||||
{
|
|
||||||
return TryStopPull(pullableUid, pullable);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TryStartPull(pullerUid, pullableUid, pullableComp: pullable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TogglePull(EntityUid pullerUid, PullerComponent puller)
|
|
||||||
{
|
|
||||||
if (!TryComp<PullableComponent>(puller.Pulling, out var pullable))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return TogglePull(puller.Pulling.Value, pullerUid, pullable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, EntityUid? user = null,
|
|
||||||
PullerComponent? pullerComp = null, PullableComponent? pullableComp = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(pullerUid, ref pullerComp, false) ||
|
|
||||||
!Resolve(pullableUid, ref pullableComp, false))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pullerComp.Pulling == pullableUid)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (!CanPull(pullerUid, pullableUid))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!EntityManager.TryGetComponent<PhysicsComponent>(pullerUid, out var pullerPhysics) ||
|
|
||||||
!EntityManager.TryGetComponent<PhysicsComponent>(pullableUid, out var pullablePhysics))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that the puller is not currently pulling anything.
|
|
||||||
var oldPullable = pullerComp.Pulling;
|
|
||||||
|
|
||||||
if (oldPullable != null)
|
|
||||||
{
|
|
||||||
// Well couldn't stop the old one.
|
|
||||||
if (!TryStopPull(oldPullable.Value, pullableComp, user))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var pullAttempt = new PullAttemptEvent(pullerUid, pullableUid);
|
|
||||||
RaiseLocalEvent(pullerUid, pullAttempt);
|
|
||||||
|
|
||||||
if (pullAttempt.Cancelled)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
RaiseLocalEvent(pullableUid, pullAttempt);
|
|
||||||
|
|
||||||
if (pullAttempt.Cancelled)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Pulling confirmed
|
|
||||||
|
|
||||||
_interaction.DoContactInteraction(pullableUid, pullerUid);
|
|
||||||
|
|
||||||
// Use net entity so it's consistent across client and server.
|
|
||||||
pullableComp.PullJointId = $"pull-joint-{GetNetEntity(pullableUid)}";
|
|
||||||
|
|
||||||
pullerComp.Pulling = pullableUid;
|
|
||||||
pullableComp.Puller = pullerUid;
|
|
||||||
|
|
||||||
// joint state handling will manage its own state
|
|
||||||
if (!_timing.ApplyingState)
|
|
||||||
{
|
|
||||||
// Joint startup
|
|
||||||
var union = _physics.GetHardAABB(pullerUid).Union(_physics.GetHardAABB(pullableUid, body: pullablePhysics));
|
|
||||||
var length = Math.Max((float) union.Size.X, (float) union.Size.Y) * 0.75f;
|
|
||||||
|
|
||||||
var joint = _joints.CreateDistanceJoint(pullableUid, pullerUid, id: pullableComp.PullJointId);
|
|
||||||
joint.CollideConnected = false;
|
|
||||||
// This maximum has to be there because if the object is constrained too closely, the clamping goes backwards and asserts.
|
|
||||||
joint.MaxLength = Math.Max(1.0f, length);
|
|
||||||
joint.Length = length * 0.75f;
|
|
||||||
joint.MinLength = 0f;
|
|
||||||
joint.Stiffness = 1f;
|
|
||||||
|
|
||||||
_physics.SetFixedRotation(pullableUid, pullableComp.FixedRotationOnPull, body: pullablePhysics);
|
|
||||||
}
|
|
||||||
|
|
||||||
pullableComp.PrevFixedRotation = pullablePhysics.FixedRotation;
|
|
||||||
|
|
||||||
// Messaging
|
|
||||||
var message = new PullStartedMessage(pullerUid, pullableUid);
|
|
||||||
_alertsSystem.ShowAlert(pullerUid, AlertType.Pulling);
|
|
||||||
_alertsSystem.ShowAlert(pullableUid, AlertType.Pulled);
|
|
||||||
|
|
||||||
RaiseLocalEvent(pullerUid, message);
|
|
||||||
RaiseLocalEvent(pullableUid, message);
|
|
||||||
|
|
||||||
Dirty(pullerUid, pullerComp);
|
|
||||||
Dirty(pullableUid, pullableComp);
|
|
||||||
|
|
||||||
_adminLogger.Add(LogType.Action, LogImpact.Low,
|
|
||||||
$"{ToPrettyString(pullerUid):user} started pulling {ToPrettyString(pullableUid):target}");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryStopPull(EntityUid pullableUid, PullableComponent pullable, EntityUid? user = null)
|
|
||||||
{
|
|
||||||
var pullerUidNull = pullable.Puller;
|
|
||||||
|
|
||||||
if (pullerUidNull == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var pullerUid = pullerUidNull.Value;
|
|
||||||
var msg = new AttemptStopPullingEvent(user);
|
|
||||||
RaiseLocalEvent(pullableUid, msg, true);
|
|
||||||
|
|
||||||
if (msg.Cancelled)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Stop pulling confirmed!
|
|
||||||
if (!_timing.ApplyingState)
|
|
||||||
{
|
|
||||||
if (TryComp<PhysicsComponent>(pullableUid, out var pullablePhysics))
|
|
||||||
{
|
|
||||||
_physics.SetFixedRotation(pullableUid, pullable.PrevFixedRotation, body: pullablePhysics);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Joint shutdown
|
|
||||||
if (pullable.PullJointId != null)
|
|
||||||
{
|
|
||||||
_joints.RemoveJoint(pullableUid, pullable.PullJointId);
|
|
||||||
pullable.PullJointId = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CleanupPulling(pullableUid, pullable);
|
|
||||||
|
|
||||||
// Messaging
|
|
||||||
var message = new PullStoppedMessage(pullerUid, pullableUid);
|
|
||||||
_alertsSystem.ClearAlert(pullerUid, AlertType.Pulling);
|
|
||||||
_alertsSystem.ClearAlert(pullableUid, AlertType.Pulled);
|
|
||||||
_modifierSystem.RefreshMovementSpeedModifiers(pullerUid);
|
|
||||||
_adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(pullerUid):user} stopped pulling {ToPrettyString(pullableUid):target}");
|
|
||||||
|
|
||||||
RaiseLocalEvent(pullerUid, message);
|
|
||||||
RaiseLocalEvent(pullableUid, message);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,6 +9,7 @@ using Content.Shared.Maps;
|
|||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
using Content.Shared.Movement.Components;
|
using Content.Shared.Movement.Components;
|
||||||
using Content.Shared.Movement.Events;
|
using Content.Shared.Movement.Events;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
using Content.Shared.Tag;
|
using Content.Shared.Tag;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
@@ -22,7 +23,6 @@ using Robust.Shared.Physics.Controllers;
|
|||||||
using Robust.Shared.Physics.Systems;
|
using Robust.Shared.Physics.Systems;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using PullableComponent = Content.Shared.Movement.Pulling.Components.PullableComponent;
|
|
||||||
|
|
||||||
namespace Content.Shared.Movement.Systems
|
namespace Content.Shared.Movement.Systems
|
||||||
{
|
{
|
||||||
@@ -53,7 +53,7 @@ namespace Content.Shared.Movement.Systems
|
|||||||
protected EntityQuery<MovementSpeedModifierComponent> ModifierQuery;
|
protected EntityQuery<MovementSpeedModifierComponent> ModifierQuery;
|
||||||
protected EntityQuery<PhysicsComponent> PhysicsQuery;
|
protected EntityQuery<PhysicsComponent> PhysicsQuery;
|
||||||
protected EntityQuery<RelayInputMoverComponent> RelayQuery;
|
protected EntityQuery<RelayInputMoverComponent> RelayQuery;
|
||||||
protected EntityQuery<PullableComponent> PullableQuery;
|
protected EntityQuery<SharedPullableComponent> PullableQuery;
|
||||||
protected EntityQuery<TransformComponent> XformQuery;
|
protected EntityQuery<TransformComponent> XformQuery;
|
||||||
protected EntityQuery<CanMoveInAirComponent> CanMoveInAirQuery;
|
protected EntityQuery<CanMoveInAirComponent> CanMoveInAirQuery;
|
||||||
protected EntityQuery<NoRotateOnMoveComponent> NoRotateQuery;
|
protected EntityQuery<NoRotateOnMoveComponent> NoRotateQuery;
|
||||||
@@ -85,7 +85,7 @@ namespace Content.Shared.Movement.Systems
|
|||||||
RelayTargetQuery = GetEntityQuery<MovementRelayTargetComponent>();
|
RelayTargetQuery = GetEntityQuery<MovementRelayTargetComponent>();
|
||||||
PhysicsQuery = GetEntityQuery<PhysicsComponent>();
|
PhysicsQuery = GetEntityQuery<PhysicsComponent>();
|
||||||
RelayQuery = GetEntityQuery<RelayInputMoverComponent>();
|
RelayQuery = GetEntityQuery<RelayInputMoverComponent>();
|
||||||
PullableQuery = GetEntityQuery<PullableComponent>();
|
PullableQuery = GetEntityQuery<SharedPullableComponent>();
|
||||||
XformQuery = GetEntityQuery<TransformComponent>();
|
XformQuery = GetEntityQuery<TransformComponent>();
|
||||||
NoRotateQuery = GetEntityQuery<NoRotateOnMoveComponent>();
|
NoRotateQuery = GetEntityQuery<NoRotateOnMoveComponent>();
|
||||||
CanMoveInAirQuery = GetEntityQuery<CanMoveInAirComponent>();
|
CanMoveInAirQuery = GetEntityQuery<CanMoveInAirComponent>();
|
||||||
@@ -381,7 +381,7 @@ namespace Content.Shared.Movement.Systems
|
|||||||
!otherCollider.CanCollide ||
|
!otherCollider.CanCollide ||
|
||||||
((collider.CollisionMask & otherCollider.CollisionLayer) == 0 &&
|
((collider.CollisionMask & otherCollider.CollisionLayer) == 0 &&
|
||||||
(otherCollider.CollisionMask & collider.CollisionLayer) == 0) ||
|
(otherCollider.CollisionMask & collider.CollisionLayer) == 0) ||
|
||||||
(TryComp(otherCollider.Owner, out PullableComponent? pullable) && pullable.BeingPulled))
|
(TryComp(otherCollider.Owner, out SharedPullableComponent? pullable) && pullable.BeingPulled))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
57
Content.Shared/Pulling/Components/PullableComponent.cs
Normal file
57
Content.Shared/Pulling/Components/PullableComponent.cs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Pulling.Components
|
||||||
|
{
|
||||||
|
// Before you try to add another type than SharedPullingStateManagementSystem, consider the can of worms you may be opening!
|
||||||
|
[NetworkedComponent, AutoGenerateComponentState]
|
||||||
|
[Access(typeof(SharedPullingStateManagementSystem))]
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed partial class SharedPullableComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The current entity pulling this component.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public EntityUid? Puller { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The pull joint.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public string? PullJointId { get; set; }
|
||||||
|
|
||||||
|
public bool BeingPulled => Puller != null;
|
||||||
|
|
||||||
|
[Access(typeof(SharedPullingStateManagementSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
|
||||||
|
public EntityCoordinates? MovingTo { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If the physics component has FixedRotation should we keep it upon being pulled
|
||||||
|
/// </summary>
|
||||||
|
[Access(typeof(SharedPullingSystem), Other = AccessPermissions.ReadExecute)]
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("fixedRotation")]
|
||||||
|
public bool FixedRotationOnPull { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// What the pullable's fixedrotation was set to before being pulled.
|
||||||
|
/// </summary>
|
||||||
|
[Access(typeof(SharedPullingSystem), Other = AccessPermissions.ReadExecute)]
|
||||||
|
[ViewVariables]
|
||||||
|
public bool PrevFixedRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised when a request is made to stop pulling an entity.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class StopPullingEvent : CancellableEntityEventArgs
|
||||||
|
{
|
||||||
|
public EntityUid? User { get; }
|
||||||
|
|
||||||
|
public StopPullingEvent(EntityUid? uid = null)
|
||||||
|
{
|
||||||
|
User = uid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
23
Content.Shared/Pulling/Components/SharedPullerComponent.cs
Normal file
23
Content.Shared/Pulling/Components/SharedPullerComponent.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
|
namespace Content.Shared.Pulling.Components
|
||||||
|
{
|
||||||
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
|
[Access(typeof(SharedPullingStateManagementSystem))]
|
||||||
|
public sealed partial class SharedPullerComponent : Component
|
||||||
|
{
|
||||||
|
// Before changing how this is updated, please see SharedPullerSystem.RefreshMovementSpeed
|
||||||
|
public float WalkSpeedModifier => Pulling == default ? 1.0f : 0.95f;
|
||||||
|
|
||||||
|
public float SprintSpeedModifier => Pulling == default ? 1.0f : 0.95f;
|
||||||
|
|
||||||
|
[DataField, AutoNetworkedField]
|
||||||
|
public EntityUid? Pulling { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Does this entity need hands to be able to pull something?
|
||||||
|
/// </summary>
|
||||||
|
[DataField("needsHands")]
|
||||||
|
public bool NeedsHands = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Content.Shared/Pulling/Events/PullAttemptEvent.cs
Normal file
11
Content.Shared/Pulling/Events/PullAttemptEvent.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using Robust.Shared.Physics.Components;
|
||||||
|
|
||||||
|
namespace Content.Shared.Physics.Pull
|
||||||
|
{
|
||||||
|
public sealed class PullAttemptEvent : PullMessage
|
||||||
|
{
|
||||||
|
public PullAttemptEvent(PhysicsComponent puller, PhysicsComponent pulled) : base(puller, pulled) { }
|
||||||
|
|
||||||
|
public bool Cancelled { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
16
Content.Shared/Pulling/Events/PullMessage.cs
Normal file
16
Content.Shared/Pulling/Events/PullMessage.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using Robust.Shared.Physics.Components;
|
||||||
|
|
||||||
|
namespace Content.Shared.Physics.Pull
|
||||||
|
{
|
||||||
|
public abstract class PullMessage : EntityEventArgs
|
||||||
|
{
|
||||||
|
public readonly PhysicsComponent Puller;
|
||||||
|
public readonly PhysicsComponent Pulled;
|
||||||
|
|
||||||
|
protected PullMessage(PhysicsComponent puller, PhysicsComponent pulled)
|
||||||
|
{
|
||||||
|
Puller = puller;
|
||||||
|
Pulled = pulled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
12
Content.Shared/Pulling/Events/PullStartedMessage.cs
Normal file
12
Content.Shared/Pulling/Events/PullStartedMessage.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Robust.Shared.Physics.Components;
|
||||||
|
|
||||||
|
namespace Content.Shared.Physics.Pull
|
||||||
|
{
|
||||||
|
public sealed class PullStartedMessage : PullMessage
|
||||||
|
{
|
||||||
|
public PullStartedMessage(PhysicsComponent puller, PhysicsComponent pulled) :
|
||||||
|
base(puller, pulled)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Content.Shared/Pulling/Events/PullStoppedMessage.cs
Normal file
11
Content.Shared/Pulling/Events/PullStoppedMessage.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using Robust.Shared.Physics.Components;
|
||||||
|
|
||||||
|
namespace Content.Shared.Physics.Pull
|
||||||
|
{
|
||||||
|
public sealed class PullStoppedMessage : PullMessage
|
||||||
|
{
|
||||||
|
public PullStoppedMessage(PhysicsComponent puller, PhysicsComponent pulled) : base(puller, pulled)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
Content.Shared/Pulling/PullableMoveMessage.cs
Normal file
6
Content.Shared/Pulling/PullableMoveMessage.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Content.Shared.Pulling
|
||||||
|
{
|
||||||
|
public sealed class PullableMoveMessage : EntityEventArgs
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
6
Content.Shared/Pulling/PullableStopMovingMessage.cs
Normal file
6
Content.Shared/Pulling/PullableStopMovingMessage.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Content.Shared.Pulling
|
||||||
|
{
|
||||||
|
public sealed class PullableStopMovingMessage : EntityEventArgs
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
28
Content.Shared/Pulling/Systems/SharedPullableSystem.cs
Normal file
28
Content.Shared/Pulling/Systems/SharedPullableSystem.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using Content.Shared.ActionBlocker;
|
||||||
|
using Content.Shared.Mobs.Systems;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
|
using Content.Shared.Movement.Events;
|
||||||
|
|
||||||
|
namespace Content.Shared.Pulling.Systems
|
||||||
|
{
|
||||||
|
public sealed class SharedPullableSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
|
||||||
|
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||||
|
[Dependency] private readonly SharedPullingSystem _pullSystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<SharedPullableComponent, MoveInputEvent>(OnRelayMoveInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRelayMoveInput(EntityUid uid, SharedPullableComponent component, ref MoveInputEvent args)
|
||||||
|
{
|
||||||
|
var entity = args.Entity;
|
||||||
|
if (_mobState.IsIncapacitated(entity) || !_blocker.CanMove(entity)) return;
|
||||||
|
|
||||||
|
_pullSystem.TryStopPull(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
90
Content.Shared/Pulling/Systems/SharedPullerSystem.cs
Normal file
90
Content.Shared/Pulling/Systems/SharedPullerSystem.cs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
using Content.Shared.Administration.Logs;
|
||||||
|
using Content.Shared.Alert;
|
||||||
|
using Content.Shared.Database;
|
||||||
|
using Content.Shared.Hands;
|
||||||
|
using Content.Shared.Movement.Systems;
|
||||||
|
using Content.Shared.Physics.Pull;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
|
namespace Content.Shared.Pulling.Systems
|
||||||
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
|
public sealed class SharedPullerSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly SharedPullingStateManagementSystem _why = default!;
|
||||||
|
[Dependency] private readonly SharedPullingSystem _pullSystem = default!;
|
||||||
|
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifierSystem = default!;
|
||||||
|
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||||
|
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<SharedPullerComponent, PullStartedMessage>(PullerHandlePullStarted);
|
||||||
|
SubscribeLocalEvent<SharedPullerComponent, PullStoppedMessage>(PullerHandlePullStopped);
|
||||||
|
SubscribeLocalEvent<SharedPullerComponent, VirtualItemDeletedEvent>(OnVirtualItemDeleted);
|
||||||
|
SubscribeLocalEvent<SharedPullerComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovespeed);
|
||||||
|
SubscribeLocalEvent<SharedPullerComponent, ComponentShutdown>(OnPullerShutdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPullerShutdown(EntityUid uid, SharedPullerComponent component, ComponentShutdown args)
|
||||||
|
{
|
||||||
|
_why.ForceDisconnectPuller(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnVirtualItemDeleted(EntityUid uid, SharedPullerComponent component, VirtualItemDeletedEvent args)
|
||||||
|
{
|
||||||
|
if (component.Pulling == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (component.Pulling == args.BlockingEntity)
|
||||||
|
{
|
||||||
|
if (EntityManager.TryGetComponent<SharedPullableComponent>(args.BlockingEntity, out var comp))
|
||||||
|
{
|
||||||
|
_pullSystem.TryStopPull(comp, uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PullerHandlePullStarted(
|
||||||
|
EntityUid uid,
|
||||||
|
SharedPullerComponent component,
|
||||||
|
PullStartedMessage args)
|
||||||
|
{
|
||||||
|
if (args.Puller.Owner != uid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_alertsSystem.ShowAlert(component.Owner, AlertType.Pulling);
|
||||||
|
|
||||||
|
RefreshMovementSpeed(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PullerHandlePullStopped(
|
||||||
|
EntityUid uid,
|
||||||
|
SharedPullerComponent component,
|
||||||
|
PullStoppedMessage args)
|
||||||
|
{
|
||||||
|
if (args.Puller.Owner != uid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var euid = component.Owner;
|
||||||
|
if (_alertsSystem.IsShowingAlert(euid, AlertType.Pulling))
|
||||||
|
_adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(euid):user} stopped pulling {ToPrettyString(args.Pulled.Owner):target}");
|
||||||
|
_alertsSystem.ClearAlert(euid, AlertType.Pulling);
|
||||||
|
|
||||||
|
RefreshMovementSpeed(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRefreshMovespeed(EntityUid uid, SharedPullerComponent component, RefreshMovementSpeedModifiersEvent args)
|
||||||
|
{
|
||||||
|
args.ModifySpeed(component.WalkSpeedModifier, component.SprintSpeedModifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshMovementSpeed(SharedPullerComponent component)
|
||||||
|
{
|
||||||
|
_movementSpeedModifierSystem.RefreshMovementSpeedModifiers(component.Owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,196 @@
|
|||||||
|
using Content.Shared.Physics.Pull;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Physics;
|
||||||
|
using Robust.Shared.Physics.Components;
|
||||||
|
using Robust.Shared.Physics.Systems;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
|
||||||
|
namespace Content.Shared.Pulling
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This is the core of pulling state management.
|
||||||
|
/// Because pulling state is such a mess to get right, all writes to pulling state must go through this class.
|
||||||
|
/// </summary>
|
||||||
|
[UsedImplicitly]
|
||||||
|
public sealed class SharedPullingStateManagementSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly SharedJointSystem _jointSystem = default!;
|
||||||
|
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<SharedPullableComponent, ComponentShutdown>(OnShutdown);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnShutdown(EntityUid uid, SharedPullableComponent component, ComponentShutdown args)
|
||||||
|
{
|
||||||
|
if (component.Puller != null)
|
||||||
|
ForceRelationship(null, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A WARNING:
|
||||||
|
// The following 2 functions are the most internal part of the pulling system's relationship management.
|
||||||
|
// They do not expect to be cancellable.
|
||||||
|
private void ForceDisconnect(SharedPullerComponent puller, SharedPullableComponent pullable)
|
||||||
|
{
|
||||||
|
var pullerPhysics = EntityManager.GetComponent<PhysicsComponent>(puller.Owner);
|
||||||
|
var pullablePhysics = EntityManager.GetComponent<PhysicsComponent>(pullable.Owner);
|
||||||
|
|
||||||
|
// MovingTo shutdown
|
||||||
|
ForceSetMovingTo(pullable, null);
|
||||||
|
|
||||||
|
// Joint shutdown
|
||||||
|
if (!_timing.ApplyingState && // During state-handling, joint component will handle its own state.
|
||||||
|
pullable.PullJointId != null &&
|
||||||
|
TryComp(puller.Owner, out JointComponent? jointComp))
|
||||||
|
{
|
||||||
|
if (jointComp.GetJoints.TryGetValue(pullable.PullJointId, out var j))
|
||||||
|
_jointSystem.RemoveJoint(j);
|
||||||
|
}
|
||||||
|
pullable.PullJointId = null;
|
||||||
|
|
||||||
|
// State shutdown
|
||||||
|
puller.Pulling = null;
|
||||||
|
pullable.Puller = null;
|
||||||
|
|
||||||
|
// Messaging
|
||||||
|
var message = new PullStoppedMessage(pullerPhysics, pullablePhysics);
|
||||||
|
|
||||||
|
RaiseLocalEvent(puller.Owner, message, broadcast: false);
|
||||||
|
|
||||||
|
if (Initialized(pullable.Owner))
|
||||||
|
RaiseLocalEvent(pullable.Owner, message, true);
|
||||||
|
|
||||||
|
// Networking
|
||||||
|
Dirty(puller);
|
||||||
|
Dirty(pullable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ForceRelationship(SharedPullerComponent? puller, SharedPullableComponent? pullable)
|
||||||
|
{
|
||||||
|
if (_timing.ApplyingState)
|
||||||
|
return;
|
||||||
|
;
|
||||||
|
if (pullable != null && puller != null && (puller.Pulling == pullable.Owner))
|
||||||
|
{
|
||||||
|
// Already done
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start by disconnecting the pullable from whatever it is currently connected to.
|
||||||
|
var pullableOldPullerE = pullable?.Puller;
|
||||||
|
if (pullableOldPullerE != null)
|
||||||
|
{
|
||||||
|
ForceDisconnect(EntityManager.GetComponent<SharedPullerComponent>(pullableOldPullerE.Value), pullable!);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue with the puller.
|
||||||
|
var pullerOldPullableE = puller?.Pulling;
|
||||||
|
if (pullerOldPullableE != null)
|
||||||
|
{
|
||||||
|
ForceDisconnect(puller!, EntityManager.GetComponent<SharedPullableComponent>(pullerOldPullableE.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// And now for the actual connection (if any).
|
||||||
|
|
||||||
|
if (puller != null && pullable != null)
|
||||||
|
{
|
||||||
|
var pullerPhysics = EntityManager.GetComponent<PhysicsComponent>(puller.Owner);
|
||||||
|
var pullablePhysics = EntityManager.GetComponent<PhysicsComponent>(pullable.Owner);
|
||||||
|
pullable.PullJointId = $"pull-joint-{pullable.Owner}";
|
||||||
|
|
||||||
|
// State startup
|
||||||
|
puller.Pulling = pullable.Owner;
|
||||||
|
pullable.Puller = puller.Owner;
|
||||||
|
|
||||||
|
// joint state handling will manage its own state
|
||||||
|
if (!_timing.ApplyingState)
|
||||||
|
{
|
||||||
|
// Joint startup
|
||||||
|
var union = _physics.GetHardAABB(puller.Owner).Union(_physics.GetHardAABB(pullable.Owner, body: pullablePhysics));
|
||||||
|
var length = Math.Max(union.Size.X, union.Size.Y) * 0.75f;
|
||||||
|
|
||||||
|
var joint = _jointSystem.CreateDistanceJoint(pullablePhysics.Owner, pullerPhysics.Owner, id: pullable.PullJointId);
|
||||||
|
joint.CollideConnected = false;
|
||||||
|
// This maximum has to be there because if the object is constrained too closely, the clamping goes backwards and asserts.
|
||||||
|
joint.MaxLength = Math.Max(1.0f, length);
|
||||||
|
joint.Length = length * 0.75f;
|
||||||
|
joint.MinLength = 0f;
|
||||||
|
joint.Stiffness = 1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Messaging
|
||||||
|
var message = new PullStartedMessage(pullerPhysics, pullablePhysics);
|
||||||
|
|
||||||
|
RaiseLocalEvent(puller.Owner, message, broadcast: false);
|
||||||
|
RaiseLocalEvent(pullable.Owner, message, true);
|
||||||
|
|
||||||
|
// Networking
|
||||||
|
Dirty(puller);
|
||||||
|
Dirty(pullable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For OnRemove use only.
|
||||||
|
public void ForceDisconnectPuller(SharedPullerComponent puller)
|
||||||
|
{
|
||||||
|
// DO NOT ADD ADDITIONAL LOGIC IN THIS FUNCTION. Do it in ForceRelationship.
|
||||||
|
ForceRelationship(puller, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For OnRemove use only.
|
||||||
|
public void ForceDisconnectPullable(SharedPullableComponent pullable)
|
||||||
|
{
|
||||||
|
// DO NOT ADD ADDITIONAL LOGIC IN THIS FUNCTION. Do it in ForceRelationship.
|
||||||
|
ForceRelationship(null, pullable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ForceSetMovingTo(SharedPullableComponent pullable, EntityCoordinates? movingTo)
|
||||||
|
{
|
||||||
|
if (_timing.ApplyingState)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (pullable.MovingTo == movingTo)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't allow setting a MovingTo if there's no puller.
|
||||||
|
// The other half of this guarantee (shutting down a MovingTo if the puller goes away) is enforced in ForceRelationship.
|
||||||
|
if (pullable.Puller == null && movingTo != null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pullable.MovingTo = movingTo;
|
||||||
|
Dirty(pullable);
|
||||||
|
|
||||||
|
if (movingTo == null)
|
||||||
|
{
|
||||||
|
RaiseLocalEvent(pullable.Owner, new PullableStopMovingMessage(), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RaiseLocalEvent(pullable.Owner, new PullableMoveMessage(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Changes if the entity needs a hand in order to be able to pull objects.
|
||||||
|
/// </summary>
|
||||||
|
public void ChangeHandRequirement(EntityUid uid, bool needsHands, SharedPullerComponent? comp)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref comp, false))
|
||||||
|
return;
|
||||||
|
|
||||||
|
comp.NeedsHands = needsHands;
|
||||||
|
|
||||||
|
Dirty(uid, comp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
239
Content.Shared/Pulling/Systems/SharedPullingSystem.Actions.cs
Normal file
239
Content.Shared/Pulling/Systems/SharedPullingSystem.Actions.cs
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
using Content.Shared.ActionBlocker;
|
||||||
|
using Content.Shared.Administration.Logs;
|
||||||
|
using Content.Shared.Buckle.Components;
|
||||||
|
using Content.Shared.Database;
|
||||||
|
using Content.Shared.Hands.EntitySystems;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Shared.Physics.Pull;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
|
using Content.Shared.Pulling.Events;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Physics;
|
||||||
|
using Robust.Shared.Physics.Components;
|
||||||
|
using Robust.Shared.Physics.Systems;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Shared.Pulling
|
||||||
|
{
|
||||||
|
public abstract partial class SharedPullingSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
|
||||||
|
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||||
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
||||||
|
[Dependency] private readonly SharedInteractionSystem _interaction = default!;
|
||||||
|
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||||
|
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||||
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
|
||||||
|
public bool CanPull(EntityUid puller, EntityUid pulled)
|
||||||
|
{
|
||||||
|
if (!EntityManager.TryGetComponent<SharedPullerComponent>(puller, out var comp))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (comp.NeedsHands && !_handsSystem.TryGetEmptyHand(puller, out _))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_blocker.CanInteract(puller, pulled))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!EntityManager.TryGetComponent<PhysicsComponent>(pulled, out var physics))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (physics.BodyType == BodyType.Static)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (puller == pulled)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_containerSystem.IsEntityInContainer(puller) || _containerSystem.IsEntityInContainer(pulled))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EntityManager.TryGetComponent(puller, out BuckleComponent? buckle))
|
||||||
|
{
|
||||||
|
// Prevent people pulling the chair they're on, etc.
|
||||||
|
if (buckle is { PullStrap: false, Buckled: true } && (buckle.LastEntityBuckledTo == pulled))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var getPulled = new BeingPulledAttemptEvent(puller, pulled);
|
||||||
|
RaiseLocalEvent(pulled, getPulled, true);
|
||||||
|
var startPull = new StartPullAttemptEvent(puller, pulled);
|
||||||
|
RaiseLocalEvent(puller, startPull, true);
|
||||||
|
return (!startPull.Cancelled && !getPulled.Cancelled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TogglePull(EntityUid puller, SharedPullableComponent pullable)
|
||||||
|
{
|
||||||
|
if (pullable.Puller == puller)
|
||||||
|
{
|
||||||
|
return TryStopPull(pullable);
|
||||||
|
}
|
||||||
|
return TryStartPull(puller, pullable.Owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- Core attempted actions --
|
||||||
|
|
||||||
|
public bool TryStopPull(SharedPullableComponent pullable, EntityUid? user = null)
|
||||||
|
{
|
||||||
|
if (_timing.ApplyingState)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!pullable.BeingPulled)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var msg = new StopPullingEvent(user);
|
||||||
|
RaiseLocalEvent(pullable.Owner, msg, true);
|
||||||
|
|
||||||
|
if (msg.Cancelled) return false;
|
||||||
|
|
||||||
|
// Stop pulling confirmed!
|
||||||
|
|
||||||
|
if (TryComp<PhysicsComponent>(pullable.Owner, out var pullablePhysics))
|
||||||
|
{
|
||||||
|
_physics.SetFixedRotation(pullable.Owner, pullable.PrevFixedRotation, body: pullablePhysics);
|
||||||
|
}
|
||||||
|
|
||||||
|
_pullSm.ForceRelationship(null, pullable);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryStartPull(EntityUid puller, EntityUid pullable)
|
||||||
|
{
|
||||||
|
if (!EntityManager.TryGetComponent(puller, out SharedPullerComponent? pullerComp))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!EntityManager.TryGetComponent(pullable, out SharedPullableComponent? pullableComp))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return TryStartPull(pullerComp, pullableComp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The main "start pulling" function.
|
||||||
|
public bool TryStartPull(SharedPullerComponent puller, SharedPullableComponent pullable)
|
||||||
|
{
|
||||||
|
if (_timing.ApplyingState)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (puller.Pulling == pullable.Owner)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Pulling a new object : Perform sanity checks.
|
||||||
|
|
||||||
|
if (!CanPull(puller.Owner, pullable.Owner))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!EntityManager.TryGetComponent<PhysicsComponent>(puller.Owner, out var pullerPhysics))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!EntityManager.TryGetComponent<PhysicsComponent>(pullable.Owner, out var pullablePhysics))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that the puller is not currently pulling anything.
|
||||||
|
// If this isn't done, then it happens too late, and the start/stop messages go out of order,
|
||||||
|
// and next thing you know it thinks it's not pulling anything even though it is!
|
||||||
|
|
||||||
|
var oldPullable = puller.Pulling;
|
||||||
|
if (oldPullable != null)
|
||||||
|
{
|
||||||
|
if (EntityManager.TryGetComponent(oldPullable.Value, out SharedPullableComponent? oldPullableComp))
|
||||||
|
{
|
||||||
|
if (!TryStopPull(oldPullableComp))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Warning("Well now you've done it, haven't you? Someone transferred pulling (onto {0}) while presently pulling something that has no Pullable component (on {1})!", pullable.Owner, oldPullable);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that the pullable is not currently being pulled.
|
||||||
|
// Same sort of reasons as before.
|
||||||
|
|
||||||
|
var oldPuller = pullable.Puller;
|
||||||
|
if (oldPuller != null)
|
||||||
|
{
|
||||||
|
if (!TryStopPull(pullable))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue with pulling process.
|
||||||
|
|
||||||
|
var pullAttempt = new PullAttemptEvent(pullerPhysics, pullablePhysics);
|
||||||
|
|
||||||
|
RaiseLocalEvent(puller.Owner, pullAttempt, broadcast: false);
|
||||||
|
|
||||||
|
if (pullAttempt.Cancelled)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RaiseLocalEvent(pullable.Owner, pullAttempt, true);
|
||||||
|
|
||||||
|
if (pullAttempt.Cancelled)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_interaction.DoContactInteraction(pullable.Owner, puller.Owner);
|
||||||
|
|
||||||
|
_pullSm.ForceRelationship(puller, pullable);
|
||||||
|
pullable.PrevFixedRotation = pullablePhysics.FixedRotation;
|
||||||
|
_physics.SetFixedRotation(pullable.Owner, pullable.FixedRotationOnPull, body: pullablePhysics);
|
||||||
|
_adminLogger.Add(LogType.Action, LogImpact.Low,
|
||||||
|
$"{ToPrettyString(puller.Owner):user} started pulling {ToPrettyString(pullable.Owner):target}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryMoveTo(SharedPullableComponent pullable, EntityCoordinates to)
|
||||||
|
{
|
||||||
|
if (pullable.Puller == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!EntityManager.HasComponent<PhysicsComponent>(pullable.Owner))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pullSm.ForceSetMovingTo(pullable, to);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopMoveTo(SharedPullableComponent pullable)
|
||||||
|
{
|
||||||
|
_pullSm.ForceSetMovingTo(pullable, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
243
Content.Shared/Pulling/Systems/SharedPullingSystem.cs
Normal file
243
Content.Shared/Pulling/Systems/SharedPullingSystem.cs
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Content.Shared.Alert;
|
||||||
|
using Content.Shared.GameTicking;
|
||||||
|
using Content.Shared.Input;
|
||||||
|
using Content.Shared.Physics.Pull;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
|
using Content.Shared.Verbs;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
|
using Robust.Shared.Input.Binding;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Physics;
|
||||||
|
using Robust.Shared.Physics.Events;
|
||||||
|
using Robust.Shared.Physics.Systems;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
|
namespace Content.Shared.Pulling
|
||||||
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
|
public abstract partial class SharedPullingSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly SharedPullingStateManagementSystem _pullSm = default!;
|
||||||
|
[Dependency] private readonly AlertsSystem _alertsSystem = default!;
|
||||||
|
[Dependency] private readonly SharedJointSystem _joints = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A mapping of pullers to the entity that they are pulling.
|
||||||
|
/// </summary>
|
||||||
|
private readonly Dictionary<EntityUid, EntityUid> _pullers =
|
||||||
|
new();
|
||||||
|
|
||||||
|
private readonly HashSet<SharedPullableComponent> _moving = new();
|
||||||
|
private readonly HashSet<SharedPullableComponent> _stoppedMoving = new();
|
||||||
|
|
||||||
|
public IReadOnlySet<SharedPullableComponent> Moving => _moving;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
UpdatesOutsidePrediction = true;
|
||||||
|
|
||||||
|
SubscribeLocalEvent<RoundRestartCleanupEvent>(Reset);
|
||||||
|
SubscribeLocalEvent<PullStartedMessage>(OnPullStarted);
|
||||||
|
SubscribeLocalEvent<PullStoppedMessage>(OnPullStopped);
|
||||||
|
SubscribeLocalEvent<EntInsertedIntoContainerMessage>(HandleContainerInsert);
|
||||||
|
SubscribeLocalEvent<SharedPullableComponent, JointRemovedEvent>(OnJointRemoved);
|
||||||
|
SubscribeLocalEvent<SharedPullableComponent, CollisionChangeEvent>(OnPullableCollisionChange);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<SharedPullableComponent, PullStartedMessage>(PullableHandlePullStarted);
|
||||||
|
SubscribeLocalEvent<SharedPullableComponent, PullStoppedMessage>(PullableHandlePullStopped);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<SharedPullableComponent, GetVerbsEvent<Verb>>(AddPullVerbs);
|
||||||
|
|
||||||
|
CommandBinds.Builder
|
||||||
|
.Bind(ContentKeyFunctions.MovePulledObject, new PointerInputCmdHandler(HandleMovePulledObject))
|
||||||
|
.Register<SharedPullingSystem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPullableCollisionChange(EntityUid uid, SharedPullableComponent component, ref CollisionChangeEvent args)
|
||||||
|
{
|
||||||
|
if (component.PullJointId != null && !args.CanCollide)
|
||||||
|
{
|
||||||
|
_joints.RemoveJoint(uid, component.PullJointId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnJointRemoved(EntityUid uid, SharedPullableComponent component, JointRemovedEvent args)
|
||||||
|
{
|
||||||
|
if (component.Puller != args.OtherEntity)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Do we have some other join with our Puller?
|
||||||
|
// or alternatively:
|
||||||
|
// TODO track the relevant joint.
|
||||||
|
|
||||||
|
if (TryComp(uid, out JointComponent? joints))
|
||||||
|
{
|
||||||
|
foreach (var jt in joints.GetJoints.Values)
|
||||||
|
{
|
||||||
|
if (jt.BodyAUid == component.Puller || jt.BodyBUid == component.Puller)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No more joints with puller -> force stop pull.
|
||||||
|
_pullSm.ForceDisconnectPullable(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddPullVerbs(EntityUid uid, SharedPullableComponent component, GetVerbsEvent<Verb> args)
|
||||||
|
{
|
||||||
|
if (!args.CanAccess || !args.CanInteract)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Are they trying to pull themselves up by their bootstraps?
|
||||||
|
if (args.User == args.Target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//TODO VERB ICONS add pulling icon
|
||||||
|
if (component.Puller == args.User)
|
||||||
|
{
|
||||||
|
Verb verb = new()
|
||||||
|
{
|
||||||
|
Text = Loc.GetString("pulling-verb-get-data-text-stop-pulling"),
|
||||||
|
Act = () => TryStopPull(component, args.User),
|
||||||
|
DoContactInteraction = false // pulling handle its own contact interaction.
|
||||||
|
};
|
||||||
|
args.Verbs.Add(verb);
|
||||||
|
}
|
||||||
|
else if (CanPull(args.User, args.Target))
|
||||||
|
{
|
||||||
|
Verb verb = new()
|
||||||
|
{
|
||||||
|
Text = Loc.GetString("pulling-verb-get-data-text"),
|
||||||
|
Act = () => TryStartPull(args.User, args.Target),
|
||||||
|
DoContactInteraction = false // pulling handle its own contact interaction.
|
||||||
|
};
|
||||||
|
args.Verbs.Add(verb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Raise a "you are being pulled" alert if the pulled entity has alerts.
|
||||||
|
private void PullableHandlePullStarted(EntityUid uid, SharedPullableComponent component, PullStartedMessage args)
|
||||||
|
{
|
||||||
|
if (args.Pulled.Owner != uid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_alertsSystem.ShowAlert(uid, AlertType.Pulled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PullableHandlePullStopped(EntityUid uid, SharedPullableComponent component, PullStoppedMessage args)
|
||||||
|
{
|
||||||
|
if (args.Pulled.Owner != uid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_alertsSystem.ClearAlert(uid, AlertType.Pulled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsPulled(EntityUid uid, SharedPullableComponent? component = null)
|
||||||
|
{
|
||||||
|
return Resolve(uid, ref component, false) && component.BeingPulled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
|
||||||
|
_moving.ExceptWith(_stoppedMoving);
|
||||||
|
_stoppedMoving.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset(RoundRestartCleanupEvent ev)
|
||||||
|
{
|
||||||
|
_pullers.Clear();
|
||||||
|
_moving.Clear();
|
||||||
|
_stoppedMoving.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPullStarted(PullStartedMessage message)
|
||||||
|
{
|
||||||
|
SetPuller(message.Puller.Owner, message.Pulled.Owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPullStopped(PullStoppedMessage message)
|
||||||
|
{
|
||||||
|
RemovePuller(message.Puller.Owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void OnPullableMove(EntityUid uid, SharedPullableComponent component, PullableMoveMessage args)
|
||||||
|
{
|
||||||
|
_moving.Add(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void OnPullableStopMove(EntityUid uid, SharedPullableComponent component, PullableStopMovingMessage args)
|
||||||
|
{
|
||||||
|
_stoppedMoving.Add(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: When Joint networking is less shitcodey fix this to use a dedicated joints message.
|
||||||
|
private void HandleContainerInsert(EntInsertedIntoContainerMessage message)
|
||||||
|
{
|
||||||
|
if (TryComp(message.Entity, out SharedPullableComponent? pullable))
|
||||||
|
{
|
||||||
|
TryStopPull(pullable);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TryComp(message.Entity, out SharedPullerComponent? puller))
|
||||||
|
{
|
||||||
|
if (puller.Pulling == null) return;
|
||||||
|
|
||||||
|
if (!TryComp(puller.Pulling.Value, out SharedPullableComponent? pulling))
|
||||||
|
return;
|
||||||
|
|
||||||
|
TryStopPull(pulling);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool HandleMovePulledObject(ICommonSession? session, EntityCoordinates coords, EntityUid uid)
|
||||||
|
{
|
||||||
|
if (session?.AttachedEntity is not { } player ||
|
||||||
|
!player.IsValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!TryGetPulled(player, out var pulled))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!TryComp(pulled.Value, out SharedPullableComponent? pullable))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (_containerSystem.IsEntityInContainer(player))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
TryMoveTo(pullable, coords);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetPuller(EntityUid puller, EntityUid pulled)
|
||||||
|
{
|
||||||
|
_pullers[puller] = pulled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool RemovePuller(EntityUid puller)
|
||||||
|
{
|
||||||
|
return _pullers.Remove(puller);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityUid GetPulled(EntityUid by)
|
||||||
|
{
|
||||||
|
return _pullers.GetValueOrDefault(by);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetPulled(EntityUid by, [NotNullWhen(true)] out EntityUid? pulled)
|
||||||
|
{
|
||||||
|
return (pulled = GetPulled(by)) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsPulling(EntityUid puller)
|
||||||
|
{
|
||||||
|
return _pullers.ContainsKey(puller);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Content.Shared.Lock;
|
using Content.Shared.Lock;
|
||||||
using Content.Shared.Movement.Pulling.Components;
|
using Content.Shared.Pulling;
|
||||||
using Content.Shared.Movement.Pulling.Systems;
|
using Content.Shared.Pulling.Components;
|
||||||
using Content.Shared.Security.Components;
|
using Content.Shared.Security.Components;
|
||||||
using Robust.Shared.Physics.Systems;
|
using Robust.Shared.Physics.Systems;
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ public sealed class DeployableBarrierSystem : EntitySystem
|
|||||||
[Dependency] private readonly FixtureSystem _fixtures = default!;
|
[Dependency] private readonly FixtureSystem _fixtures = default!;
|
||||||
[Dependency] private readonly SharedPointLightSystem _pointLight = default!;
|
[Dependency] private readonly SharedPointLightSystem _pointLight = default!;
|
||||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||||
[Dependency] private readonly PullingSystem _pulling = default!;
|
[Dependency] private readonly SharedPullingSystem _pulling = default!;
|
||||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
@@ -58,8 +58,8 @@ public sealed class DeployableBarrierSystem : EntitySystem
|
|||||||
var state = isDeployed ? DeployableBarrierState.Deployed : DeployableBarrierState.Idle;
|
var state = isDeployed ? DeployableBarrierState.Deployed : DeployableBarrierState.Idle;
|
||||||
_appearance.SetData(uid, DeployableBarrierVisuals.State, state);
|
_appearance.SetData(uid, DeployableBarrierVisuals.State, state);
|
||||||
|
|
||||||
if (TryComp(uid, out PullableComponent? pullable))
|
if (TryComp(uid, out SharedPullableComponent? pullable))
|
||||||
_pulling.TryStopPull(uid, pullable);
|
_pulling.TryStopPull(pullable);
|
||||||
|
|
||||||
SharedPointLightComponent? pointLight = null;
|
SharedPointLightComponent? pointLight = null;
|
||||||
if (_pointLight.ResolveLight(uid, ref pointLight))
|
if (_pointLight.ResolveLight(uid, ref pointLight))
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Shared.Ghost;
|
using Content.Shared.Ghost;
|
||||||
using Content.Shared.Movement.Pulling.Components;
|
|
||||||
using Content.Shared.Movement.Pulling.Systems;
|
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Projectiles;
|
using Content.Shared.Projectiles;
|
||||||
|
using Content.Shared.Pulling;
|
||||||
|
using Content.Shared.Pulling.Components;
|
||||||
using Content.Shared.Teleportation.Components;
|
using Content.Shared.Teleportation.Components;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
@@ -28,7 +28,7 @@ public abstract class SharedPortalSystem : EntitySystem
|
|||||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
[Dependency] private readonly PullingSystem _pulling = default!;
|
[Dependency] private readonly SharedPullingSystem _pulling = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||||
|
|
||||||
private const string PortalFixture = "portalFixture";
|
private const string PortalFixture = "portalFixture";
|
||||||
@@ -93,15 +93,15 @@ public abstract class SharedPortalSystem : EntitySystem
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// break pulls before portal enter so we dont break shit
|
// break pulls before portal enter so we dont break shit
|
||||||
if (TryComp<PullableComponent>(subject, out var pullable) && pullable.BeingPulled)
|
if (TryComp<SharedPullableComponent>(subject, out var pullable) && pullable.BeingPulled)
|
||||||
{
|
{
|
||||||
_pulling.TryStopPull(subject, pullable);
|
_pulling.TryStopPull(pullable);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryComp<PullerComponent>(subject, out var pullerComp)
|
if (TryComp<SharedPullerComponent>(subject, out var pulling)
|
||||||
&& TryComp<PullableComponent>(pullerComp.Pulling, out var subjectPulling))
|
&& pulling.Pulling != null && TryComp<SharedPullableComponent>(pulling.Pulling.Value, out var subjectPulling))
|
||||||
{
|
{
|
||||||
_pulling.TryStopPull(subject, subjectPulling);
|
_pulling.TryStopPull(subjectPulling);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if they came from another portal, just return and wait for them to exit the portal
|
// if they came from another portal, just return and wait for them to exit the portal
|
||||||
|
|||||||
@@ -20,11 +20,6 @@ public sealed class ThrowingSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
public const float ThrowAngularImpulse = 5f;
|
public const float ThrowAngularImpulse = 5f;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Speed cap on rotation in case of click-spam.
|
|
||||||
/// </summary>
|
|
||||||
public const float ThrowAngularCap = 3f * MathF.PI;
|
|
||||||
|
|
||||||
public const float PushbackDefault = 2f;
|
public const float PushbackDefault = 2f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -47,17 +42,15 @@ public sealed class ThrowingSystem : EntitySystem
|
|||||||
float strength = 1.0f,
|
float strength = 1.0f,
|
||||||
EntityUid? user = null,
|
EntityUid? user = null,
|
||||||
float pushbackRatio = PushbackDefault,
|
float pushbackRatio = PushbackDefault,
|
||||||
bool recoil = true,
|
|
||||||
bool animated = true,
|
|
||||||
bool playSound = true)
|
bool playSound = true)
|
||||||
{
|
{
|
||||||
var thrownPos = _transform.GetMapCoordinates(uid);
|
var thrownPos = Transform(uid).MapPosition;
|
||||||
var mapPos = _transform.ToMapCoordinates(coordinates);
|
var mapPos = coordinates.ToMap(EntityManager, _transform);
|
||||||
|
|
||||||
if (mapPos.MapId != thrownPos.MapId)
|
if (mapPos.MapId != thrownPos.MapId)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TryThrow(uid, mapPos.Position - thrownPos.Position, strength, user, pushbackRatio, recoil: recoil, animated: animated, playSound: playSound);
|
TryThrow(uid, mapPos.Position - thrownPos.Position, strength, user, pushbackRatio, playSound);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -72,8 +65,6 @@ public sealed class ThrowingSystem : EntitySystem
|
|||||||
float strength = 1.0f,
|
float strength = 1.0f,
|
||||||
EntityUid? user = null,
|
EntityUid? user = null,
|
||||||
float pushbackRatio = PushbackDefault,
|
float pushbackRatio = PushbackDefault,
|
||||||
bool recoil = true,
|
|
||||||
bool animated = true,
|
|
||||||
bool playSound = true)
|
bool playSound = true)
|
||||||
{
|
{
|
||||||
var physicsQuery = GetEntityQuery<PhysicsComponent>();
|
var physicsQuery = GetEntityQuery<PhysicsComponent>();
|
||||||
@@ -81,6 +72,7 @@ public sealed class ThrowingSystem : EntitySystem
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var projectileQuery = GetEntityQuery<ProjectileComponent>();
|
var projectileQuery = GetEntityQuery<ProjectileComponent>();
|
||||||
|
var tagQuery = GetEntityQuery<TagComponent>();
|
||||||
|
|
||||||
TryThrow(
|
TryThrow(
|
||||||
uid,
|
uid,
|
||||||
@@ -90,7 +82,8 @@ public sealed class ThrowingSystem : EntitySystem
|
|||||||
projectileQuery,
|
projectileQuery,
|
||||||
strength,
|
strength,
|
||||||
user,
|
user,
|
||||||
pushbackRatio, recoil: recoil, animated: animated, playSound: playSound);
|
pushbackRatio,
|
||||||
|
playSound);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -108,8 +101,6 @@ public sealed class ThrowingSystem : EntitySystem
|
|||||||
float strength = 1.0f,
|
float strength = 1.0f,
|
||||||
EntityUid? user = null,
|
EntityUid? user = null,
|
||||||
float pushbackRatio = PushbackDefault,
|
float pushbackRatio = PushbackDefault,
|
||||||
bool recoil = true,
|
|
||||||
bool animated = true,
|
|
||||||
bool playSound = true)
|
bool playSound = true)
|
||||||
{
|
{
|
||||||
if (strength <= 0 || direction == Vector2Helpers.Infinity || direction == Vector2Helpers.NaN || direction == Vector2.Zero)
|
if (strength <= 0 || direction == Vector2Helpers.Infinity || direction == Vector2Helpers.NaN || direction == Vector2.Zero)
|
||||||
@@ -125,17 +116,12 @@ public sealed class ThrowingSystem : EntitySystem
|
|||||||
if (projectileQuery.TryGetComponent(uid, out var proj) && !proj.OnlyCollideWhenShot)
|
if (projectileQuery.TryGetComponent(uid, out var proj) && !proj.OnlyCollideWhenShot)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var comp = new ThrownItemComponent
|
var comp = new ThrownItemComponent();
|
||||||
{
|
comp.Thrower = user;
|
||||||
Thrower = user,
|
|
||||||
Animate = animated,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Estimate time to arrival so we can apply OnGround status and slow it much faster.
|
// Estimate time to arrival so we can apply OnGround status and slow it much faster.
|
||||||
var time = direction.Length() / strength;
|
var time = direction.Length() / strength;
|
||||||
comp.ThrownTime = _gameTiming.CurTime;
|
comp.ThrownTime = _gameTiming.CurTime;
|
||||||
// TODO: This is a bandaid, don't do this.
|
|
||||||
// if you want to force landtime have the caller handle it or add a new method.
|
|
||||||
// did we launch this with something stronger than our hands?
|
// did we launch this with something stronger than our hands?
|
||||||
if (TryComp<HandsComponent>(comp.Thrower, out var hands) && strength > hands.ThrowForceMultiplier)
|
if (TryComp<HandsComponent>(comp.Thrower, out var hands) && strength > hands.ThrowForceMultiplier)
|
||||||
comp.LandTime = comp.ThrownTime + TimeSpan.FromSeconds(time);
|
comp.LandTime = comp.ThrownTime + TimeSpan.FromSeconds(time);
|
||||||
@@ -180,8 +166,7 @@ public sealed class ThrowingSystem : EntitySystem
|
|||||||
if (user == null)
|
if (user == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (recoil)
|
_recoil.KickCamera(user.Value, -direction * 0.04f);
|
||||||
_recoil.KickCamera(user.Value, -direction * 0.04f);
|
|
||||||
|
|
||||||
// Give thrower an impulse in the other direction
|
// Give thrower an impulse in the other direction
|
||||||
if (pushbackRatio != 0.0f &&
|
if (pushbackRatio != 0.0f &&
|
||||||
|
|||||||
@@ -8,12 +8,6 @@ namespace Content.Shared.Throwing
|
|||||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
|
||||||
public sealed partial class ThrownItemComponent : Component
|
public sealed partial class ThrownItemComponent : Component
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Should the in-air throwing animation play.
|
|
||||||
/// </summary>
|
|
||||||
[DataField, AutoNetworkedField]
|
|
||||||
public bool Animate = true;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The entity that threw this entity.
|
/// The entity that threw this entity.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ using Content.Shared.Administration.Logs;
|
|||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Gravity;
|
using Content.Shared.Gravity;
|
||||||
using Content.Shared.Physics;
|
using Content.Shared.Physics;
|
||||||
using Content.Shared.Movement.Pulling.Events;
|
using Content.Shared.Physics.Pull;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Physics;
|
using Robust.Shared.Physics;
|
||||||
using Robust.Shared.Physics.Components;
|
using Robust.Shared.Physics.Components;
|
||||||
using Robust.Shared.Physics.Events;
|
using Robust.Shared.Physics.Events;
|
||||||
@@ -93,8 +94,8 @@ namespace Content.Shared.Throwing
|
|||||||
private void HandlePullStarted(PullStartedMessage message)
|
private void HandlePullStarted(PullStartedMessage message)
|
||||||
{
|
{
|
||||||
// TODO: this isn't directed so things have to be done the bad way
|
// TODO: this isn't directed so things have to be done the bad way
|
||||||
if (EntityManager.TryGetComponent(message.PulledUid, out ThrownItemComponent? thrownItemComponent))
|
if (EntityManager.TryGetComponent(message.Pulled.Owner, out ThrownItemComponent? thrownItemComponent))
|
||||||
StopThrow(message.PulledUid, thrownItemComponent);
|
StopThrow(message.Pulled.Owner, thrownItemComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopThrow(EntityUid uid, ThrownItemComponent thrownItemComponent)
|
public void StopThrow(EntityUid uid, ThrownItemComponent thrownItemComponent)
|
||||||
|
|||||||
Reference in New Issue
Block a user