2022-11-18 22:08:28 +01:00
using Content.Shared.Buckle.Components ;
using Content.Shared.DragDrop ;
using Content.Shared.Interaction ;
using Robust.Shared.GameStates ;
namespace Content.Shared.Buckle ;
public abstract partial class SharedBuckleSystem
{
[Dependency] private readonly SharedInteractionSystem _interactions = default ! ;
private void InitializeStrap ( )
{
2022-12-23 23:55:31 -05:00
SubscribeLocalEvent < StrapComponent , MoveEvent > ( OnStrapRotate ) ;
SubscribeLocalEvent < StrapComponent , ComponentHandleState > ( OnStrapHandleState ) ;
2023-02-14 00:29:34 +11:00
SubscribeLocalEvent < StrapComponent , CanDropTargetEvent > ( OnStrapCanDropOn ) ;
2022-11-18 22:08:28 +01:00
}
2022-12-23 23:55:31 -05:00
private void OnStrapHandleState ( EntityUid uid , StrapComponent component , ref ComponentHandleState args )
2022-11-18 22:08:28 +01:00
{
if ( args . Current is not StrapComponentState state )
return ;
component . Position = state . Position ;
component . BuckleOffsetUnclamped = state . BuckleOffsetClamped ;
component . BuckledEntities . Clear ( ) ;
component . BuckledEntities . UnionWith ( state . BuckledEntities ) ;
component . MaxBuckleDistance = state . MaxBuckleDistance ;
}
2022-12-23 23:55:31 -05:00
private void OnStrapRotate ( EntityUid uid , StrapComponent component , ref MoveEvent args )
2022-11-18 22:08:28 +01:00
{
// TODO: This looks dirty af.
// On rotation of a strap, reattach all buckled entities.
// This fixes buckle offsets and draw depths.
// This is mega cursed. Please somebody save me from Mr Buckle's wild ride.
// Oh god I'm back here again. Send help.
// Consider a chair that has a player strapped to it. Then the client receives a new server state, showing
// that the player entity has moved elsewhere, and the chair has rotated. If the client applies the player
// state, then the chairs transform comp state, and then the buckle state. The transform state will
// forcefully teleport the player back to the chair (client-side only). This causes even more issues if the
// chair was teleporting in from nullspace after having left PVS.
//
// One option is to just never trigger re-buckles during state application.
// another is to.. just not do this? Like wtf is this code. But I CBF with buckle atm.
if ( GameTiming . ApplyingState | | args . NewRotation = = args . OldRotation )
return ;
foreach ( var buckledEntity in component . BuckledEntities )
{
2022-12-23 23:55:31 -05:00
if ( ! EntityManager . TryGetComponent ( buckledEntity , out BuckleComponent ? buckled ) )
2022-11-18 22:08:28 +01:00
{
continue ;
}
if ( ! buckled . Buckled | | buckled . LastEntityBuckledTo ! = uid )
{
Logger . Error ( $"A moving strap entity {ToPrettyString(uid)} attempted to re-parent an entity that does not 'belong' to it {ToPrettyString(buckledEntity)}" ) ;
continue ;
}
ReAttach ( buckledEntity , component , buckle : buckled ) ;
Dirty ( buckled ) ;
}
}
protected bool StrapCanDragDropOn (
EntityUid strapId ,
EntityUid user ,
EntityUid target ,
EntityUid buckleId ,
2022-12-23 23:55:31 -05:00
StrapComponent ? strap = null ,
BuckleComponent ? buckle = null )
2022-11-18 22:08:28 +01:00
{
if ( ! Resolve ( strapId , ref strap , false ) | |
! Resolve ( buckleId , ref buckle , false ) )
{
return false ;
}
bool Ignored ( EntityUid entity ) = > entity = = user | | entity = = buckleId | | entity = = target ;
return _interactions . InRangeUnobstructed ( target , buckleId , buckle . Range , predicate : Ignored ) ;
}
2023-02-14 00:29:34 +11:00
private void OnStrapCanDropOn ( EntityUid uid , StrapComponent strap , ref CanDropTargetEvent args )
2022-11-18 22:08:28 +01:00
{
2023-02-14 00:29:34 +11:00
args . CanDrop = StrapCanDragDropOn ( uid , args . User , uid , args . Dragged , strap ) ;
2022-11-18 22:08:28 +01:00
args . Handled = true ;
}
}