2021-11-24 16:52:31 -06:00
using Content.Shared.Administration.Logs ;
2021-11-28 14:56:53 +01:00
using Content.Shared.Database ;
2021-08-31 22:46:11 +10:00
using Content.Shared.Hands.Components ;
2021-05-31 17:13:40 +10:00
using Content.Shared.Physics ;
2021-06-09 22:19:39 +02:00
using Content.Shared.Physics.Pull ;
2021-08-31 22:46:11 +10:00
using Robust.Shared.Containers ;
2021-03-08 04:09:59 +11:00
using Robust.Shared.GameObjects ;
2021-10-12 21:58:11 +02:00
using Robust.Shared.GameStates ;
2021-08-23 15:02:03 +10:00
using Robust.Shared.IoC ;
2021-05-31 17:13:40 +10:00
using Robust.Shared.Log ;
2021-03-08 04:09:59 +11:00
using Robust.Shared.Physics ;
2021-05-27 11:47:39 +01:00
using Robust.Shared.Physics.Dynamics ;
2022-01-21 01:38:35 -08:00
using System.Linq ;
2021-03-08 04:09:59 +11:00
2021-06-09 22:19:39 +02:00
namespace Content.Shared.Throwing
2021-03-08 04:09:59 +11:00
{
/// <summary>
/// Handles throwing landing and collisions.
/// </summary>
2021-12-01 18:32:37 +11:00
public sealed class ThrownItemSystem : EntitySystem
2021-03-08 04:09:59 +11:00
{
2021-09-29 00:16:00 +10:00
[Dependency] private readonly SharedContainerSystem _containerSystem = default ! ;
2021-11-24 16:52:31 -06:00
[Dependency] private readonly SharedAdminLogSystem _adminLogSystem = default ! ;
2021-12-01 18:32:37 +11:00
[Dependency] private readonly FixtureSystem _fixtures = default ! ;
2021-08-23 15:02:03 +10:00
2021-05-31 17:13:40 +10:00
private const string ThrowingFixture = "throw-fixture" ;
2021-03-08 04:09:59 +11:00
public override void Initialize ( )
{
base . Initialize ( ) ;
2021-05-27 11:47:39 +01:00
SubscribeLocalEvent < ThrownItemComponent , PhysicsSleepMessage > ( HandleSleep ) ;
2021-05-31 17:13:40 +10:00
SubscribeLocalEvent < ThrownItemComponent , StartCollideEvent > ( HandleCollision ) ;
SubscribeLocalEvent < ThrownItemComponent , PreventCollideEvent > ( PreventCollision ) ;
SubscribeLocalEvent < ThrownItemComponent , ThrownEvent > ( ThrowItem ) ;
2021-10-12 21:58:11 +02:00
SubscribeLocalEvent < ThrownItemComponent , ComponentGetState > ( OnGetState ) ;
SubscribeLocalEvent < ThrownItemComponent , ComponentHandleState > ( OnHandleState ) ;
2021-05-27 11:47:39 +01:00
SubscribeLocalEvent < PullStartedMessage > ( HandlePullStarted ) ;
2021-03-08 04:09:59 +11:00
}
2021-10-12 21:58:11 +02:00
private void OnGetState ( EntityUid uid , ThrownItemComponent component , ref ComponentGetState args )
{
2021-12-03 15:53:09 +01:00
args . State = new ThrownItemComponentState ( component . Thrower ) ;
2021-10-12 21:58:11 +02:00
}
private void OnHandleState ( EntityUid uid , ThrownItemComponent component , ref ComponentHandleState args )
{
2021-12-05 18:09:01 +01:00
if ( args . Current is not ThrownItemComponentState { Thrower : not null } state | |
! state . Thrower . Value . IsValid ( ) )
{
2021-10-12 21:58:11 +02:00
return ;
2021-12-05 18:09:01 +01:00
}
2021-10-12 21:58:11 +02:00
2021-12-05 18:09:01 +01:00
component . Thrower = state . Thrower . Value ;
2021-10-12 21:58:11 +02:00
}
2021-05-31 17:13:40 +10:00
private void ThrowItem ( EntityUid uid , ThrownItemComponent component , ThrownEvent args )
{
2022-01-21 01:38:35 -08:00
if ( ! EntityManager . TryGetComponent ( component . Owner , out FixturesComponent ? fixturesComponent ) | |
fixturesComponent . Fixtures . Count ! = 1 ) return ;
if ( ! EntityManager . TryGetComponent ( component . Owner , out PhysicsComponent ? physicsComponent ) ) return ;
2021-05-31 17:13:40 +10:00
2022-01-21 01:38:35 -08:00
if ( fixturesComponent . Fixtures . ContainsKey ( ThrowingFixture ) )
2021-05-31 17:13:40 +10:00
{
Logger . Error ( $"Found existing throwing fixture on {component.Owner}" ) ;
return ;
}
2022-01-21 01:38:35 -08:00
var fixture = fixturesComponent . Fixtures . Values . First ( ) ;
var shape = fixture . Shape ;
var throwingFixture = new Fixture ( physicsComponent , shape ) { CollisionLayer = ( int ) CollisionGroup . ThrownItem , Hard = false , ID = ThrowingFixture } ;
_fixtures . CreateFixture ( physicsComponent , throwingFixture , manager : fixturesComponent ) ;
2021-05-31 17:13:40 +10:00
}
private void HandleCollision ( EntityUid uid , ThrownItemComponent component , StartCollideEvent args )
{
var thrower = component . Thrower ;
var otherBody = args . OtherFixture . Body ;
if ( otherBody . Owner = = thrower ) return ;
ThrowCollideInteraction ( thrower , args . OurFixture . Body , otherBody ) ;
}
private void PreventCollision ( EntityUid uid , ThrownItemComponent component , PreventCollideEvent args )
{
if ( args . BodyB . Owner = = component . Thrower )
{
args . Cancel ( ) ;
}
}
2021-05-27 11:47:39 +01:00
private void HandleSleep ( EntityUid uid , ThrownItemComponent thrownItem , PhysicsSleepMessage message )
2021-03-08 04:09:59 +11:00
{
2021-09-29 00:16:00 +10:00
StopThrow ( uid , thrownItem ) ;
2021-03-08 04:09:59 +11:00
}
2021-05-27 11:47:39 +01:00
private void HandlePullStarted ( PullStartedMessage message )
2021-03-08 04:09:59 +11:00
{
2021-05-27 11:47:39 +01:00
// TODO: this isn't directed so things have to be done the bad way
2021-12-03 15:53:09 +01:00
if ( EntityManager . TryGetComponent ( message . Pulled . Owner , out ThrownItemComponent ? thrownItemComponent ) )
StopThrow ( message . Pulled . Owner , thrownItemComponent ) ;
2021-05-27 11:47:39 +01:00
}
2021-09-29 00:16:00 +10:00
private void StopThrow ( EntityUid uid , ThrownItemComponent thrownItemComponent )
2021-05-27 11:47:39 +01:00
{
2021-09-29 00:16:00 +10:00
if ( EntityManager . TryGetComponent ( uid , out PhysicsComponent ? physicsComponent ) )
{
2021-12-01 18:32:37 +11:00
var fixture = _fixtures . GetFixtureOrNull ( physicsComponent , ThrowingFixture ) ;
2021-03-08 04:09:59 +11:00
2021-09-29 00:16:00 +10:00
if ( fixture ! = null )
{
2021-12-01 18:32:37 +11:00
_fixtures . DestroyFixture ( physicsComponent , fixture ) ;
2021-09-29 00:16:00 +10:00
}
}
2021-09-10 22:59:50 +10:00
2021-12-03 15:53:09 +01:00
EntityManager . EventBus . RaiseLocalEvent ( uid , new StopThrowEvent { User = thrownItemComponent . Thrower } ) ;
2021-09-29 00:16:00 +10:00
EntityManager . RemoveComponent < ThrownItemComponent > ( uid ) ;
}
2021-09-10 22:59:50 +10:00
2021-09-29 00:16:00 +10:00
public void LandComponent ( ThrownItemComponent thrownItem )
{
2021-12-09 12:29:27 +01:00
if ( thrownItem . Deleted | | Deleted ( thrownItem . Owner ) | | _containerSystem . IsEntityInContainer ( thrownItem . Owner ) ) return ;
2021-09-10 22:59:50 +10:00
2021-09-29 00:16:00 +10:00
var landing = thrownItem . Owner ;
2021-09-10 22:59:50 +10:00
// Unfortunately we can't check for hands containers as they have specific names.
if ( thrownItem . Owner . TryGetContainerMan ( out var containerManager ) & &
2021-12-07 22:22:34 +11:00
EntityManager . HasComponent < SharedHandsComponent > ( containerManager . Owner ) )
2021-09-10 22:59:50 +10:00
{
2021-12-03 15:53:09 +01:00
EntityManager . RemoveComponent ( landing , thrownItem ) ;
2021-09-10 22:59:50 +10:00
return ;
}
2021-11-24 16:52:31 -06:00
// Assume it's uninteresting if it has no thrower. For now anyway.
if ( thrownItem . Thrower is not null )
2021-12-14 00:22:58 +13:00
_adminLogSystem . Add ( LogType . Landed , LogImpact . Low , $"{ToPrettyString(landing):entity} thrown by {ToPrettyString(thrownItem.Thrower.Value):thrower} landed." ) ;
2021-11-24 16:52:31 -06:00
2021-12-03 15:53:09 +01:00
var landMsg = new LandEvent { User = thrownItem . Thrower } ;
RaiseLocalEvent ( landing , landMsg , false ) ;
2021-03-08 04:09:59 +11:00
}
/// <summary>
2021-08-21 09:18:23 +02:00
/// Raises collision events on the thrown and target entities.
2021-03-08 04:09:59 +11:00
/// </summary>
2021-12-04 12:59:44 +01:00
public void ThrowCollideInteraction ( EntityUid ? user , IPhysBody thrown , IPhysBody target )
2021-03-08 04:09:59 +11:00
{
2021-11-29 02:34:44 +13:00
if ( user is not null )
_adminLogSystem . Add ( LogType . ThrowHit , LogImpact . Low ,
2021-12-11 16:00:10 +01:00
$"{ToPrettyString(thrown.Owner):thrown} thrown by {ToPrettyString(user.Value):thrower} hit {ToPrettyString(target.Owner):target}." ) ;
2021-03-08 04:09:59 +11:00
// TODO: Just pass in the bodies directly
2021-12-03 15:53:09 +01:00
RaiseLocalEvent ( target . Owner , new ThrowHitByEvent ( user , thrown . Owner , target . Owner ) ) ;
RaiseLocalEvent ( thrown . Owner , new ThrowDoHitEvent ( user , thrown . Owner , target . Owner ) ) ;
2021-03-08 04:09:59 +11:00
}
}
}