Change ThrownItemComponent to be removed after flytime (#20700)
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
using System.Numerics;
|
||||
using Content.Shared.Gravity;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Projectiles;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Map;
|
||||
@@ -24,6 +23,7 @@ public sealed class ThrowingSystem : EntitySystem
|
||||
/// </summary>
|
||||
public const float FlyTime = 0.15f;
|
||||
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly SharedGravitySystem _gravity = default!;
|
||||
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
@@ -112,6 +112,13 @@ public sealed class ThrowingSystem : EntitySystem
|
||||
|
||||
var comp = EnsureComp<ThrownItemComponent>(uid);
|
||||
comp.Thrower = user;
|
||||
|
||||
// Estimate time to arrival so we can apply OnGround status and slow it much faster.
|
||||
var time = direction.Length() / strength;
|
||||
comp.ThrownTime = _gameTiming.CurTime;
|
||||
comp.LandTime = time < FlyTime ? default : comp.ThrownTime + TimeSpan.FromSeconds(time - FlyTime);
|
||||
comp.PlayLandSound = playSound;
|
||||
|
||||
ThrowingAngleComponent? throwingAngle = null;
|
||||
|
||||
// Give it a l'il spin.
|
||||
@@ -134,24 +141,13 @@ public sealed class ThrowingSystem : EntitySystem
|
||||
var impulseVector = direction.Normalized() * strength * physics.Mass;
|
||||
_physics.ApplyLinearImpulse(uid, impulseVector, body: physics);
|
||||
|
||||
// Estimate time to arrival so we can apply OnGround status and slow it much faster.
|
||||
var time = direction.Length() / strength;
|
||||
|
||||
if (time < FlyTime)
|
||||
if (comp.LandTime <= TimeSpan.Zero)
|
||||
{
|
||||
_thrownSystem.LandComponent(uid, comp, physics, playSound);
|
||||
}
|
||||
else
|
||||
{
|
||||
_physics.SetBodyStatus(physics, BodyStatus.InAir);
|
||||
|
||||
Timer.Spawn(TimeSpan.FromSeconds(time - FlyTime), () =>
|
||||
{
|
||||
if (physics.Deleted)
|
||||
return;
|
||||
|
||||
_thrownSystem.LandComponent(uid, comp, physics, playSound);
|
||||
});
|
||||
}
|
||||
|
||||
// Give thrower an impulse in the other direction
|
||||
|
||||
@@ -1,13 +1,41 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Shared.Throwing
|
||||
{
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class ThrownItemComponent : Component
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("thrower")]
|
||||
/// <summary>
|
||||
/// The entity that threw this entity.
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
|
||||
public EntityUid? Thrower { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IGameTiming.CurTime"/> timestamp at which this entity was thrown.
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
|
||||
public TimeSpan? ThrownTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Compared to <see cref="IGameTiming.CurTime"/> to land this entity, if any.
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
|
||||
public TimeSpan? LandTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not this entity was already landed.
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
|
||||
public bool Landed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not to play a sound when the entity lands.
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
|
||||
public bool PlayLandSound { get; set; }
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
|
||||
@@ -3,12 +3,11 @@ using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Physics;
|
||||
using Content.Shared.Physics.Pull;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Physics.Events;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Shared.Throwing
|
||||
{
|
||||
@@ -18,6 +17,7 @@ namespace Content.Shared.Throwing
|
||||
public sealed class ThrownItemSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly SharedBroadphaseSystem _broadphase = default!;
|
||||
[Dependency] private readonly FixtureSystem _fixtures = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
@@ -27,29 +27,18 @@ namespace Content.Shared.Throwing
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<ThrownItemComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<ThrownItemComponent, PhysicsSleepEvent>(OnSleep);
|
||||
SubscribeLocalEvent<ThrownItemComponent, StartCollideEvent>(HandleCollision);
|
||||
SubscribeLocalEvent<ThrownItemComponent, PreventCollideEvent>(PreventCollision);
|
||||
SubscribeLocalEvent<ThrownItemComponent, ThrownEvent>(ThrowItem);
|
||||
SubscribeLocalEvent<ThrownItemComponent, ComponentGetState>(OnGetState);
|
||||
SubscribeLocalEvent<ThrownItemComponent, ComponentHandleState>(OnHandleState);
|
||||
SubscribeLocalEvent<ThrownItemComponent, EntityUnpausedEvent>(OnThrownUnpaused);
|
||||
SubscribeLocalEvent<PullStartedMessage>(HandlePullStarted);
|
||||
}
|
||||
|
||||
private void OnGetState(EntityUid uid, ThrownItemComponent component, ref ComponentGetState args)
|
||||
private void OnMapInit(EntityUid uid, ThrownItemComponent component, MapInitEvent args)
|
||||
{
|
||||
args.State = new ThrownItemComponentState(GetNetEntity(component.Thrower));
|
||||
}
|
||||
|
||||
private void OnHandleState(EntityUid uid, ThrownItemComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not ThrownItemComponentState { Thrower: not null } state ||
|
||||
!state.Thrower.Value.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
component.Thrower = EnsureEntity<ThrownItemComponent>(state.Thrower.Value, uid);
|
||||
component.ThrownTime ??= _gameTiming.CurTime;
|
||||
}
|
||||
|
||||
private void ThrowItem(EntityUid uid, ThrownItemComponent component, ThrownEvent args)
|
||||
@@ -66,6 +55,14 @@ namespace Content.Shared.Throwing
|
||||
_fixtures.TryCreateFixture(uid, shape, ThrowingFixture, hard: false, collisionMask: (int) CollisionGroup.ThrownItem, manager: fixturesComponent, body: body);
|
||||
}
|
||||
|
||||
private void OnThrownUnpaused(EntityUid uid, ThrownItemComponent component, ref EntityUnpausedEvent args)
|
||||
{
|
||||
if (component.LandTime != null)
|
||||
{
|
||||
component.LandTime = component.LandTime.Value + args.PausedTime;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleCollision(EntityUid uid, ThrownItemComponent component, ref StartCollideEvent args)
|
||||
{
|
||||
if (!args.OtherFixture.Hard)
|
||||
@@ -120,9 +117,11 @@ namespace Content.Shared.Throwing
|
||||
|
||||
public void LandComponent(EntityUid uid, ThrownItemComponent thrownItem, PhysicsComponent physics, bool playSound)
|
||||
{
|
||||
if (thrownItem.Deleted || Deleted(uid))
|
||||
if (thrownItem.Landed || thrownItem.Deleted || Deleted(uid))
|
||||
return;
|
||||
|
||||
thrownItem.Landed = true;
|
||||
|
||||
// Assume it's uninteresting if it has no thrower. For now anyway.
|
||||
if (thrownItem.Thrower is not null)
|
||||
_adminLogger.Add(LogType.Landed, LogImpact.Low, $"{ToPrettyString(uid):entity} thrown by {ToPrettyString(thrownItem.Thrower.Value):thrower} landed.");
|
||||
@@ -130,8 +129,6 @@ namespace Content.Shared.Throwing
|
||||
_broadphase.RegenerateContacts(uid, physics);
|
||||
var landEvent = new LandEvent(thrownItem.Thrower, playSound);
|
||||
RaiseLocalEvent(uid, ref landEvent);
|
||||
|
||||
StopThrow(uid, thrownItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -146,5 +143,25 @@ namespace Content.Shared.Throwing
|
||||
RaiseLocalEvent(target, new ThrowHitByEvent(thrown, target, component), true);
|
||||
RaiseLocalEvent(thrown, new ThrowDoHitEvent(thrown, target, component), true);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<ThrownItemComponent, PhysicsComponent>();
|
||||
while (query.MoveNext(out var uid, out var thrown, out var physics))
|
||||
{
|
||||
if (thrown.LandTime <= _gameTiming.CurTime)
|
||||
{
|
||||
LandComponent(uid, thrown, physics, thrown.PlayLandSound);
|
||||
}
|
||||
|
||||
var stopThrowTime = (thrown.LandTime ?? thrown.ThrownTime) + TimeSpan.FromSeconds(ThrowingSystem.FlyTime);
|
||||
if (stopThrowTime <= _gameTiming.CurTime)
|
||||
{
|
||||
StopThrow(uid, thrown);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,6 +259,7 @@ public abstract partial class SharedTetherGunSystem : EntitySystem
|
||||
{
|
||||
var thrown = EnsureComp<ThrownItemComponent>(component.Tethered.Value);
|
||||
_thrown.LandComponent(component.Tethered.Value, thrown, targetPhysics, true);
|
||||
_thrown.StopThrow(component.Tethered.Value, thrown);
|
||||
}
|
||||
|
||||
_physics.SetBodyStatus(targetPhysics, BodyStatus.OnGround);
|
||||
|
||||
Reference in New Issue
Block a user