2022-05-18 12:35:44 +10:00
using System.Threading ;
2021-11-09 08:08:30 +01:00
using System.Threading.Tasks ;
2022-03-25 22:10:43 +01:00
using Content.Server.Administration.Logs ;
2021-11-09 08:08:30 +01:00
using Content.Server.Coordinates.Helpers ;
2022-06-06 09:04:40 +10:00
using Content.Server.Popups ;
2021-11-09 08:08:30 +01:00
using Content.Server.Pulling ;
using Content.Server.Tools ;
2022-04-02 16:52:44 +13:00
using Content.Shared.Construction.Components ;
using Content.Shared.Construction.EntitySystems ;
2022-03-25 22:10:43 +01:00
using Content.Shared.Database ;
2022-05-30 04:55:54 -04:00
using Content.Shared.Examine ;
2021-11-09 08:08:30 +01:00
using Content.Shared.Pulling.Components ;
2022-04-02 16:52:44 +13:00
using Content.Shared.Tools.Components ;
2022-06-06 09:04:40 +10:00
using Robust.Shared.Player ;
2021-11-09 08:08:30 +01:00
namespace Content.Server.Construction
{
2022-04-02 16:52:44 +13:00
public sealed class AnchorableSystem : SharedAnchorableSystem
2021-11-09 08:08:30 +01:00
{
2022-05-28 23:41:17 -07:00
[Dependency] private readonly IAdminLogManager _adminLogger = default ! ;
2022-06-06 09:04:40 +10:00
[Dependency] private readonly PopupSystem _popup = default ! ;
2021-11-09 08:08:30 +01:00
[Dependency] private readonly ToolSystem _toolSystem = default ! ;
[Dependency] private readonly PullingSystem _pullingSystem = default ! ;
2022-05-18 12:35:44 +10:00
public override void Initialize ( )
{
base . Initialize ( ) ;
2022-06-06 09:04:40 +10:00
SubscribeLocalEvent < AnchorableComponent , TryAnchorCompletedEvent > ( OnAnchorComplete ) ;
SubscribeLocalEvent < AnchorableComponent , TryAnchorCancelledEvent > ( OnAnchorCancelled ) ;
SubscribeLocalEvent < AnchorableComponent , TryUnanchorCompletedEvent > ( OnUnanchorComplete ) ;
SubscribeLocalEvent < AnchorableComponent , TryUnanchorCancelledEvent > ( OnUnanchorCancelled ) ;
2022-05-30 04:55:54 -04:00
SubscribeLocalEvent < AnchorableComponent , ExaminedEvent > ( OnAnchoredExamine ) ;
}
private void OnAnchoredExamine ( EntityUid uid , AnchorableComponent component , ExaminedEvent args )
{
var isAnchored = Comp < TransformComponent > ( uid ) . Anchored ;
var messageId = isAnchored ? "examinable-anchored" : "examinable-unanchored" ;
args . PushMarkup ( Loc . GetString ( messageId , ( "target" , uid ) ) ) ;
2022-05-18 12:35:44 +10:00
}
2022-06-06 09:04:40 +10:00
private void OnUnanchorCancelled ( EntityUid uid , AnchorableComponent component , TryUnanchorCancelledEvent args )
2022-05-18 12:35:44 +10:00
{
component . CancelToken = null ;
}
2022-06-06 09:04:40 +10:00
private void OnUnanchorComplete ( EntityUid uid , AnchorableComponent component , TryUnanchorCompletedEvent args )
2022-05-18 12:35:44 +10:00
{
component . CancelToken = null ;
var xform = Transform ( uid ) ;
RaiseLocalEvent ( uid , new BeforeUnanchoredEvent ( args . User , args . Using ) , false ) ;
xform . Anchored = false ;
RaiseLocalEvent ( uid , new UserUnanchoredEvent ( args . User , args . Using ) , false ) ;
2022-06-06 09:04:40 +10:00
_popup . PopupEntity ( Loc . GetString ( "anchorable-unanchored" ) , uid , Filter . Pvs ( uid , entityManager : EntityManager ) ) ;
2022-05-28 23:41:17 -07:00
_adminLogger . Add (
2022-05-18 12:35:44 +10:00
LogType . Action ,
LogImpact . Low ,
$"{EntityManager.ToPrettyString(args.User):user} unanchored {EntityManager.ToPrettyString(uid):anchored} using {EntityManager.ToPrettyString(args.Using):using}"
) ;
}
2022-06-06 09:04:40 +10:00
private void OnAnchorCancelled ( EntityUid uid , AnchorableComponent component , TryAnchorCancelledEvent args )
2022-05-18 12:35:44 +10:00
{
component . CancelToken = null ;
}
2022-06-06 09:04:40 +10:00
private void OnAnchorComplete ( EntityUid uid , AnchorableComponent component , TryAnchorCompletedEvent args )
2022-05-18 12:35:44 +10:00
{
component . CancelToken = null ;
var xform = Transform ( uid ) ;
// Snap rotation to cardinal (multiple of 90)
var rot = xform . LocalRotation ;
xform . LocalRotation = Math . Round ( rot / ( Math . PI / 2 ) ) * ( Math . PI / 2 ) ;
if ( TryComp < SharedPullableComponent > ( uid , out var pullable ) & & pullable . Puller ! = null )
{
_pullingSystem . TryStopPull ( pullable ) ;
}
if ( component . Snap )
xform . Coordinates = xform . Coordinates . SnapToGrid ( ) ;
RaiseLocalEvent ( uid , new BeforeAnchoredEvent ( args . User , args . Using ) , false ) ;
xform . Anchored = true ;
RaiseLocalEvent ( uid , new UserAnchoredEvent ( args . User , args . Using ) , false ) ;
2022-06-06 09:04:40 +10:00
_popup . PopupEntity ( Loc . GetString ( "anchorable-anchored" ) , uid , Filter . Pvs ( uid , entityManager : EntityManager ) ) ;
2022-05-28 23:41:17 -07:00
_adminLogger . Add (
2022-05-18 12:35:44 +10:00
LogType . Action ,
LogImpact . Low ,
$"{EntityManager.ToPrettyString(args.User):user} anchored {EntityManager.ToPrettyString(uid):anchored} using {EntityManager.ToPrettyString(args.Using):using}"
) ;
}
2021-11-09 08:08:30 +01:00
/// <summary>
/// Checks if a tool can change the anchored status.
/// </summary>
/// <returns>true if it is valid, false otherwise</returns>
2022-05-18 12:35:44 +10:00
private bool Valid ( EntityUid uid , EntityUid userUid , EntityUid usingUid , bool anchoring , AnchorableComponent ? anchorable = null , ToolComponent ? usingTool = null )
2021-11-09 08:08:30 +01:00
{
2022-05-18 12:35:44 +10:00
if ( ! Resolve ( uid , ref anchorable ) | |
anchorable . CancelToken ! = null )
2021-11-09 08:08:30 +01:00
return false ;
if ( ! Resolve ( usingUid , ref usingTool ) )
return false ;
BaseAnchoredAttemptEvent attempt =
anchoring ? new AnchorAttemptEvent ( userUid , usingUid ) : new UnanchorAttemptEvent ( userUid , usingUid ) ;
// Need to cast the event or it will be raised as BaseAnchoredAttemptEvent.
if ( anchoring )
RaiseLocalEvent ( uid , ( AnchorAttemptEvent ) attempt , false ) ;
else
RaiseLocalEvent ( uid , ( UnanchorAttemptEvent ) attempt , false ) ;
if ( attempt . Cancelled )
return false ;
2022-05-18 12:35:44 +10:00
return true ;
2021-11-09 08:08:30 +01:00
}
/// <summary>
/// Tries to anchor the entity.
/// </summary>
/// <returns>true if anchored, false otherwise</returns>
2022-05-18 12:35:44 +10:00
private void TryAnchor ( EntityUid uid , EntityUid userUid , EntityUid usingUid ,
2021-11-09 08:08:30 +01:00
AnchorableComponent ? anchorable = null ,
TransformComponent ? transform = null ,
SharedPullableComponent ? pullable = null ,
ToolComponent ? usingTool = null )
{
2022-05-18 12:35:44 +10:00
if ( ! Resolve ( uid , ref anchorable , ref transform ) ) return ;
2021-11-09 08:08:30 +01:00
// Optional resolves.
2022-01-11 07:43:58 +11:00
Resolve ( uid , ref pullable , false ) ;
2021-11-09 08:08:30 +01:00
2022-05-18 12:35:44 +10:00
if ( ! Resolve ( usingUid , ref usingTool ) ) return ;
2021-11-09 08:08:30 +01:00
2022-05-18 12:35:44 +10:00
if ( ! Valid ( uid , userUid , usingUid , true , anchorable , usingTool ) ) return ;
2021-11-09 08:08:30 +01:00
2022-05-18 12:35:44 +10:00
anchorable . CancelToken = new CancellationTokenSource ( ) ;
2021-11-09 08:08:30 +01:00
2022-05-18 12:35:44 +10:00
_toolSystem . UseTool ( usingUid , userUid , uid , 0f , anchorable . Delay , usingTool . Qualities ,
new TryAnchorCompletedEvent ( ) , new TryAnchorCancelledEvent ( ) , uid , cancelToken : anchorable . CancelToken . Token ) ;
2021-11-09 08:08:30 +01:00
}
/// <summary>
/// Tries to unanchor the entity.
/// </summary>
/// <returns>true if unanchored, false otherwise</returns>
2022-05-18 12:35:44 +10:00
private void TryUnAnchor ( EntityUid uid , EntityUid userUid , EntityUid usingUid ,
2021-11-09 08:08:30 +01:00
AnchorableComponent ? anchorable = null ,
TransformComponent ? transform = null ,
ToolComponent ? usingTool = null )
{
2022-05-18 12:35:44 +10:00
if ( ! Resolve ( uid , ref anchorable , ref transform ) | |
anchorable . CancelToken ! = null )
return ;
2021-11-09 08:08:30 +01:00
2022-05-18 12:35:44 +10:00
if ( ! Resolve ( usingUid , ref usingTool ) ) return ;
2021-11-09 08:08:30 +01:00
2022-05-18 12:35:44 +10:00
if ( ! Valid ( uid , userUid , usingUid , false ) ) return ;
2021-11-09 08:08:30 +01:00
2022-05-18 12:35:44 +10:00
anchorable . CancelToken = new CancellationTokenSource ( ) ;
2022-03-25 22:10:43 +01:00
2022-05-18 12:35:44 +10:00
_toolSystem . UseTool ( usingUid , userUid , uid , 0f , anchorable . Delay , usingTool . Qualities ,
new TryUnanchorCompletedEvent ( ) , new TryUnanchorCancelledEvent ( ) , uid , cancelToken : anchorable . CancelToken . Token ) ;
2021-11-09 08:08:30 +01:00
}
/// <summary>
/// Tries to toggle the anchored status of this component's owner.
/// </summary>
/// <returns>true if toggled, false otherwise</returns>
2022-05-18 12:35:44 +10:00
public override void TryToggleAnchor ( EntityUid uid , EntityUid userUid , EntityUid usingUid ,
2021-11-09 08:08:30 +01:00
AnchorableComponent ? anchorable = null ,
TransformComponent ? transform = null ,
SharedPullableComponent ? pullable = null ,
ToolComponent ? usingTool = null )
{
if ( ! Resolve ( uid , ref transform ) )
2022-05-18 12:35:44 +10:00
return ;
if ( transform . Anchored )
{
TryUnAnchor ( uid , userUid , usingUid , anchorable , transform , usingTool ) ;
}
else
{
TryAnchor ( uid , userUid , usingUid , anchorable , transform , pullable , usingTool ) ;
}
}
private abstract class AnchorEvent : EntityEventArgs
{
public EntityUid User ;
public EntityUid Using ;
public readonly TransformComponent Transform = default ! ;
}
private sealed class TryUnanchorCompletedEvent : AnchorEvent
{
}
private sealed class TryUnanchorCancelledEvent : AnchorEvent
{
}
private sealed class TryAnchorCompletedEvent : AnchorEvent
{
}
private sealed class TryAnchorCancelledEvent : AnchorEvent
{
2021-11-09 08:08:30 +01:00
}
}
}