2021-08-10 16:18:57 -07:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Threading ;
using System.Threading.Tasks ;
2021-06-09 22:19:39 +02:00
using Content.Server.DoAfter ;
using Content.Server.Hands.Components ;
2021-10-31 14:23:26 +01:00
using Content.Server.Interaction ;
2021-06-09 22:19:39 +02:00
using Content.Shared.Acts ;
2022-01-31 01:53:31 +11:00
using Content.Shared.Coordinates ;
2021-06-09 22:19:39 +02:00
using Content.Shared.Interaction ;
using Content.Shared.Interaction.Helpers ;
using Content.Shared.Item ;
2021-08-20 10:21:39 +02:00
using Content.Shared.Placeable ;
2021-09-26 15:18:45 +02:00
using Content.Shared.Popups ;
2021-07-10 17:35:33 +02:00
using Content.Shared.Sound ;
2021-11-27 19:43:19 +13:00
using Content.Shared.Stacks ;
2021-06-09 22:19:39 +02:00
using Content.Shared.Storage ;
2021-11-27 19:43:19 +13:00
using Content.Shared.Storage.Components ;
2021-07-25 08:41:50 -07:00
using Content.Shared.Whitelist ;
2019-04-15 21:11:38 -06:00
using Robust.Server.GameObjects ;
using Robust.Server.Player ;
2021-01-05 05:34:53 +00:00
using Robust.Shared.Audio ;
2021-03-01 15:24:46 -08:00
using Robust.Shared.Containers ;
2019-04-15 21:11:38 -06:00
using Robust.Shared.Enums ;
using Robust.Shared.GameObjects ;
2021-04-06 13:31:07 +10:00
using Robust.Shared.IoC ;
2019-04-15 21:11:38 -06:00
using Robust.Shared.Log ;
2021-02-03 22:07:13 +00:00
using Robust.Shared.Map ;
2021-02-11 01:13:03 -08:00
using Robust.Shared.Network ;
2021-03-21 09:12:03 -07:00
using Robust.Shared.Player ;
2020-04-20 10:36:02 +01:00
using Robust.Shared.Players ;
2021-03-05 01:08:38 +01:00
using Robust.Shared.Serialization.Manager.Attributes ;
2021-11-29 12:25:22 +13:00
using Robust.Shared.Utility ;
2020-09-08 13:30:22 +02:00
using Robust.Shared.ViewVariables ;
2018-04-22 06:11:38 -05:00
2021-06-09 22:19:39 +02:00
namespace Content.Server.Storage.Components
2018-04-22 06:11:38 -05:00
{
/// <summary>
/// Storage component for containing entities within this one, matches a UI on the client which shows stored entities
/// </summary>
2019-07-31 15:02:36 +02:00
[RegisterComponent]
[ComponentReference(typeof(IActivate))]
[ComponentReference(typeof(IStorageComponent))]
2022-01-05 02:23:01 +13:00
[ComponentReference(typeof(SharedStorageComponent))]
public class ServerStorageComponent : SharedStorageComponent , IInteractUsing , IActivate , IStorageComponent , IDestroyAct , IExAct , IAfterInteract
2018-04-22 06:11:38 -05:00
{
2021-11-27 19:43:19 +13:00
[Dependency] private readonly IEntityManager _entityManager = default ! ;
2020-07-17 11:03:07 +02:00
private const string LoggerName = "Storage" ;
2018-04-22 06:11:38 -05:00
2021-11-29 12:25:22 +13:00
public Container ? Storage ;
2021-12-03 11:11:52 +01:00
2021-12-05 18:09:01 +01:00
private readonly Dictionary < EntityUid , int > _sizeCache = new ( ) ;
2018-04-22 06:11:38 -05:00
2021-03-05 01:08:38 +01:00
[DataField("occludesLight")]
private bool _occludesLight = true ;
2021-07-25 08:41:50 -07:00
2021-03-05 01:08:38 +01:00
[DataField("quickInsert")]
2021-07-25 08:41:50 -07:00
private bool _quickInsert = false ; // Can insert storables by "attacking" them with the storage entity
2021-11-03 14:33:36 -07:00
[DataField("clickInsert")]
private bool _clickInsert = true ; // Can insert stuff by clicking the storage entity with it
2021-03-05 01:08:38 +01:00
[DataField("areaInsert")]
2021-07-25 08:41:50 -07:00
private bool _areaInsert = false ; // "Attacking" with the storage entity causes it to insert all nearby storables after a delay
2021-10-24 02:34:29 +00:00
[DataField("areaInsertRadius")]
private int _areaInsertRadius = 1 ;
2021-07-25 08:41:50 -07:00
[DataField("whitelist")]
private EntityWhitelist ? _whitelist = null ;
2020-07-17 11:03:07 +02:00
private bool _storageInitialCalculated ;
private int _storageUsed ;
2021-03-05 01:08:38 +01:00
[DataField("capacity")]
private int _storageCapacityMax = 10000 ;
2020-11-27 11:00:49 +01:00
public readonly HashSet < IPlayerSession > SubscribedSessions = new ( ) ;
2020-05-05 00:39:15 +02:00
2021-03-05 01:08:38 +01:00
[DataField("storageSoundCollection")]
2021-07-31 19:52:33 +02:00
public SoundSpecifier StorageSoundCollection { get ; set ; } = new SoundCollectionSpecifier ( "storageRustle" ) ;
2021-01-05 05:34:53 +00:00
2020-09-08 13:30:22 +02:00
[ViewVariables]
2021-12-05 18:09:01 +01:00
public override IReadOnlyList < EntityUid > ? StoredEntities = > Storage ? . ContainedEntities ;
2020-07-17 11:03:07 +02:00
2020-09-14 00:04:00 +12:00
[ViewVariables(VVAccess.ReadWrite)]
2020-07-26 08:25:53 -04:00
public bool OccludesLight
{
get = > _occludesLight ;
set
{
_occludesLight = value ;
2021-11-29 12:25:22 +13:00
if ( Storage ! = null ) Storage . OccludesLight = value ;
2020-07-26 08:25:53 -04:00
}
}
2021-11-27 19:43:19 +13:00
private void UpdateStorageVisualization ( )
{
2021-12-07 21:54:00 +11:00
if ( ! _entityManager . TryGetComponent ( Owner , out AppearanceComponent appearance ) )
2021-11-27 19:43:19 +13:00
return ;
bool open = SubscribedSessions . Count ! = 0 ;
appearance . SetData ( StorageVisuals . Open , open ) ;
appearance . SetData ( SharedBagOpenVisuals . BagState , open ? SharedBagState . Open : SharedBagState . Closed ) ;
2021-12-07 21:54:00 +11:00
if ( _entityManager . HasComponent < ItemCounterComponent > ( Owner ) )
2021-11-27 19:43:19 +13:00
appearance . SetData ( StackVisuals . Hide , ! open ) ;
}
2020-07-17 11:03:07 +02:00
private void EnsureInitialCalculated ( )
2018-04-22 06:11:38 -05:00
{
2020-07-17 11:03:07 +02:00
if ( _storageInitialCalculated )
{
return ;
}
2018-04-22 06:11:38 -05:00
2020-07-17 11:03:07 +02:00
RecalculateStorageUsed ( ) ;
_storageInitialCalculated = true ;
2018-04-22 06:11:38 -05:00
}
2018-11-11 20:04:52 +01:00
2020-07-17 11:03:07 +02:00
private void RecalculateStorageUsed ( )
2018-04-22 06:11:38 -05:00
{
2020-07-17 11:03:07 +02:00
_storageUsed = 0 ;
2022-01-31 01:53:31 +11:00
_sizeCache . Clear ( ) ;
2018-04-22 06:11:38 -05:00
2021-11-29 12:25:22 +13:00
if ( Storage = = null )
2020-07-17 11:03:07 +02:00
{
return ;
}
2021-11-29 12:25:22 +13:00
foreach ( var entity in Storage . ContainedEntities )
2020-07-17 11:03:07 +02:00
{
2021-12-05 18:09:01 +01:00
var item = _entityManager . GetComponent < SharedItemComponent > ( entity ) ;
2020-10-14 15:24:07 +02:00
_storageUsed + = item . Size ;
2022-01-31 01:53:31 +11:00
_sizeCache . Add ( entity , item . Size ) ;
2020-07-17 11:03:07 +02:00
}
2018-04-22 06:11:38 -05:00
}
/// <summary>
2020-07-17 11:03:07 +02:00
/// Verifies if an entity can be stored and if it fits
2018-04-22 06:11:38 -05:00
/// </summary>
2020-07-17 11:03:07 +02:00
/// <param name="entity">The entity to check</param>
/// <returns>true if it can be inserted, false otherwise</returns>
2021-12-05 18:09:01 +01:00
public bool CanInsert ( EntityUid entity )
2018-04-22 06:11:38 -05:00
{
2020-07-17 11:03:07 +02:00
EnsureInitialCalculated ( ) ;
2019-05-05 13:09:21 +02:00
2021-12-05 18:09:01 +01:00
if ( _entityManager . TryGetComponent ( entity , out ServerStorageComponent ? storage ) & &
2020-07-17 11:03:07 +02:00
storage . _storageCapacityMax > = _storageCapacityMax )
2018-04-22 06:11:38 -05:00
{
2020-07-17 11:03:07 +02:00
return false ;
2018-04-22 06:11:38 -05:00
}
2019-05-05 13:09:21 +02:00
2021-12-05 18:09:01 +01:00
if ( _entityManager . TryGetComponent ( entity , out SharedItemComponent ? store ) & &
2020-10-14 15:24:07 +02:00
store . Size > _storageCapacityMax - _storageUsed )
2020-07-17 11:03:07 +02:00
{
return false ;
}
2021-12-03 15:53:09 +01:00
if ( _whitelist ! = null & & ! _whitelist . IsValid ( entity ) )
2021-07-25 08:41:50 -07:00
{
return false ;
}
2021-12-05 18:09:01 +01:00
if ( _entityManager . GetComponent < TransformComponent > ( entity ) . Anchored )
2021-10-27 14:12:36 +07:00
{
return false ;
}
2020-07-17 11:03:07 +02:00
return true ;
2018-04-22 06:11:38 -05:00
}
/// <summary>
2020-07-17 11:03:07 +02:00
/// Inserts into the storage container
2018-04-22 06:11:38 -05:00
/// </summary>
2020-07-17 11:03:07 +02:00
/// <param name="entity">The entity to insert</param>
/// <returns>true if the entity was inserted, false otherwise</returns>
2021-12-05 18:09:01 +01:00
public bool Insert ( EntityUid entity )
2020-07-17 11:03:07 +02:00
{
2021-11-29 12:25:22 +13:00
return CanInsert ( entity ) & & Storage ? . Insert ( entity ) = = true ;
2020-07-17 11:03:07 +02:00
}
2021-12-05 18:09:01 +01:00
public override bool Remove ( EntityUid entity )
2018-04-22 06:11:38 -05:00
{
2020-07-17 11:03:07 +02:00
EnsureInitialCalculated ( ) ;
2021-11-29 12:25:22 +13:00
return Storage ? . Remove ( entity ) = = true ;
2019-05-05 13:09:21 +02:00
}
2020-07-17 11:03:07 +02:00
public void HandleEntityMaybeInserted ( EntInsertedIntoContainerMessage message )
2019-05-05 13:09:21 +02:00
{
2021-11-29 12:25:22 +13:00
if ( message . Container ! = Storage )
2018-04-22 06:11:38 -05:00
{
2019-05-05 13:09:21 +02:00
return ;
2018-04-22 06:11:38 -05:00
}
2019-05-05 13:09:21 +02:00
2021-07-10 17:35:33 +02:00
PlaySoundCollection ( ) ;
2020-07-17 11:03:07 +02:00
EnsureInitialCalculated ( ) ;
2021-12-03 15:53:09 +01:00
Logger . DebugS ( LoggerName , $"Storage (UID {Owner}) had entity (UID {message.Entity}) inserted into it." ) ;
2020-07-17 11:03:07 +02:00
2021-01-11 09:26:25 +01:00
var size = 0 ;
2021-12-05 18:09:01 +01:00
if ( _entityManager . TryGetComponent ( message . Entity , out SharedItemComponent ? storable ) )
2021-01-11 09:26:25 +01:00
size = storable . Size ;
_storageUsed + = size ;
_sizeCache [ message . Entity ] = size ;
2020-07-17 11:03:07 +02:00
2019-05-05 13:09:21 +02:00
UpdateClientInventories ( ) ;
2018-04-22 06:11:38 -05:00
}
2020-07-17 11:03:07 +02:00
public void HandleEntityMaybeRemoved ( EntRemovedFromContainerMessage message )
2018-04-22 06:11:38 -05:00
{
2021-11-29 12:25:22 +13:00
if ( message . Container ! = Storage )
2019-03-30 07:56:29 -05:00
{
2020-07-17 11:03:07 +02:00
return ;
2019-03-30 07:56:29 -05:00
}
2020-07-17 11:03:07 +02:00
EnsureInitialCalculated ( ) ;
2020-12-04 00:11:43 +01:00
Logger . DebugS ( LoggerName , $"Storage (UID {Owner}) had entity (UID {message.Entity}) removed from it." ) ;
2020-07-17 11:03:07 +02:00
2021-01-11 09:26:25 +01:00
if ( ! _sizeCache . TryGetValue ( message . Entity , out var size ) )
2018-04-22 06:11:38 -05:00
{
2022-01-31 01:53:31 +11:00
Logger . WarningS ( LoggerName , $"Removed entity {_entityManager.ToPrettyString(message.Entity)} without a cached size from storage {_entityManager.ToPrettyString(Owner)} at {_entityManager.GetComponent<TransformComponent>(Owner).MapPosition}" ) ;
2020-07-17 11:03:07 +02:00
RecalculateStorageUsed ( ) ;
return ;
2018-04-22 06:11:38 -05:00
}
2020-07-17 11:03:07 +02:00
2021-01-11 09:26:25 +01:00
_storageUsed - = size ;
2020-07-17 11:03:07 +02:00
UpdateClientInventories ( ) ;
2018-04-22 06:11:38 -05:00
}
/// <summary>
2020-07-17 11:03:07 +02:00
/// Inserts an entity into storage from the player's active hand
2018-04-22 06:11:38 -05:00
/// </summary>
2020-07-17 11:03:07 +02:00
/// <param name="player">The player to insert an entity from</param>
/// <returns>true if inserted, false otherwise</returns>
2021-12-05 18:09:01 +01:00
public bool PlayerInsertHeldEntity ( EntityUid player )
2018-04-22 06:11:38 -05:00
{
2020-07-17 11:03:07 +02:00
EnsureInitialCalculated ( ) ;
2018-12-13 05:49:05 -08:00
2021-12-05 18:09:01 +01:00
if ( ! _entityManager . TryGetComponent ( player , out HandsComponent ? hands ) | |
2022-01-21 01:38:35 -08:00
hands . GetActiveHandItem = = null )
2019-04-17 23:26:00 +02:00
{
return false ;
}
2022-01-21 01:38:35 -08:00
var toInsert = hands . GetActiveHandItem ;
2020-05-23 02:27:31 -07:00
2020-07-17 11:03:07 +02:00
if ( ! hands . Drop ( toInsert . Owner ) )
{
Owner . PopupMessage ( player , "Can't insert." ) ;
return false ;
}
2020-05-23 02:27:31 -07:00
2020-07-17 11:03:07 +02:00
if ( ! Insert ( toInsert . Owner ) )
{
hands . PutInHand ( toInsert ) ;
Owner . PopupMessage ( player , "Can't insert." ) ;
return false ;
}
return true ;
}
2018-04-22 06:11:38 -05:00
2021-02-03 22:07:13 +00:00
/// <summary>
/// Inserts an Entity (<paramref name="toInsert"/>) in the world into storage, informing <paramref name="player"/> if it fails.
2021-12-03 16:08:30 +01:00
/// <paramref name="toInsert"/> is *NOT* held, see <see cref="PlayerInsertHeldEntity(Robust.Shared.GameObjects.EntityUid)"/>.
2021-02-03 22:07:13 +00:00
/// </summary>
/// <param name="player">The player to insert an entity with</param>
/// <returns>true if inserted, false otherwise</returns>
2021-12-05 18:09:01 +01:00
public bool PlayerInsertEntityInWorld ( EntityUid player , EntityUid toInsert )
2021-02-03 22:07:13 +00:00
{
EnsureInitialCalculated ( ) ;
if ( ! Insert ( toInsert ) )
{
Owner . PopupMessage ( player , "Can't insert." ) ;
return false ;
}
return true ;
}
2018-04-22 06:11:38 -05:00
/// <summary>
2020-07-17 11:03:07 +02:00
/// Opens the storage UI for an entity
2018-04-22 06:11:38 -05:00
/// </summary>
2020-07-17 11:03:07 +02:00
/// <param name="entity">The entity to open the UI for</param>
2021-12-05 18:09:01 +01:00
public void OpenStorageUI ( EntityUid entity )
2018-04-22 06:11:38 -05:00
{
2021-07-10 17:35:33 +02:00
PlaySoundCollection ( ) ;
2020-07-17 11:03:07 +02:00
EnsureInitialCalculated ( ) ;
2019-07-31 16:38:24 -07:00
2021-12-05 18:09:01 +01:00
var userSession = _entityManager . GetComponent < ActorComponent > ( entity ) . PlayerSession ;
2020-07-17 11:03:07 +02:00
2021-12-05 18:09:01 +01:00
Logger . DebugS ( LoggerName , $"Storage (UID {Owner}) \" used \ " by player session (UID {userSession.AttachedEntity})." ) ;
2020-07-17 11:03:07 +02:00
SubscribeSession ( userSession ) ;
2021-10-27 18:10:40 +02:00
#pragma warning disable 618
2020-07-17 11:03:07 +02:00
SendNetworkMessage ( new OpenStorageUIMessage ( ) , userSession . ConnectedClient ) ;
2021-10-27 18:10:40 +02:00
#pragma warning restore 618
2020-07-17 11:03:07 +02:00
UpdateClientInventory ( userSession ) ;
2018-04-22 06:11:38 -05:00
}
/// <summary>
2020-07-17 11:03:07 +02:00
/// Updates the storage UI on all subscribed actors, informing them of the state of the container.
2018-04-22 06:11:38 -05:00
/// </summary>
2018-06-20 16:49:13 -04:00
private void UpdateClientInventories ( )
2018-04-22 06:11:38 -05:00
{
2020-07-17 11:03:07 +02:00
foreach ( var session in SubscribedSessions )
2018-06-20 16:49:13 -04:00
{
UpdateClientInventory ( session ) ;
}
}
/// <summary>
2020-07-17 11:03:07 +02:00
/// Updates storage UI on a client, informing them of the state of the container.
/// </summary>
/// <param name="session">The client to be updated</param>
private void UpdateClientInventory ( IPlayerSession session )
{
if ( session . AttachedEntity = = null )
{
2021-12-05 18:09:01 +01:00
Logger . DebugS ( LoggerName , $"Storage (UID {Owner}) detected no attached entity in player session (UID {session.AttachedEntity})." ) ;
2020-07-17 11:03:07 +02:00
UnsubscribeSession ( session ) ;
return ;
}
2021-11-29 12:25:22 +13:00
if ( Storage = = null )
2020-07-17 11:03:07 +02:00
{
2021-11-29 12:25:22 +13:00
Logger . WarningS ( LoggerName , $"{nameof(UpdateClientInventory)} called with null {nameof(Storage)}" ) ;
2020-07-17 11:03:07 +02:00
return ;
}
2020-10-14 15:24:07 +02:00
if ( StoredEntities = = null )
2020-07-17 11:03:07 +02:00
{
2020-10-14 15:24:07 +02:00
Logger . WarningS ( LoggerName , $"{nameof(UpdateClientInventory)} called with null {nameof(StoredEntities)}" ) ;
return ;
2020-07-17 11:03:07 +02:00
}
2021-12-05 18:09:01 +01:00
var stored = StoredEntities . Select ( e = > e ) . ToArray ( ) ;
2020-10-14 15:24:07 +02:00
2021-10-27 18:10:40 +02:00
#pragma warning disable 618
2020-10-14 15:24:07 +02:00
SendNetworkMessage ( new StorageHeldItemsMessage ( stored , _storageUsed , _storageCapacityMax ) , session . ConnectedClient ) ;
2021-10-27 18:10:40 +02:00
#pragma warning restore 618
2020-07-17 11:03:07 +02:00
}
/// <summary>
/// Adds a session to the update list.
2018-06-20 16:49:13 -04:00
/// </summary>
2020-07-17 11:03:07 +02:00
/// <param name="session">The session to add</param>
private void SubscribeSession ( IPlayerSession session )
2018-06-20 16:49:13 -04:00
{
2020-07-17 11:03:07 +02:00
EnsureInitialCalculated ( ) ;
2018-06-20 16:49:13 -04:00
if ( ! SubscribedSessions . Contains ( session ) )
{
2021-12-05 18:09:01 +01:00
Logger . DebugS ( LoggerName , $"Storage (UID {Owner}) subscribed player session (UID {session.AttachedEntity})." ) ;
2020-07-17 11:03:07 +02:00
2018-06-20 16:49:13 -04:00
session . PlayerStatusChanged + = HandlePlayerSessionChangeEvent ;
SubscribedSessions . Add ( session ) ;
}
2021-11-27 19:43:19 +13:00
if ( SubscribedSessions . Count = = 1 )
UpdateStorageVisualization ( ) ;
2018-06-20 16:49:13 -04:00
}
/// <summary>
2020-07-17 11:03:07 +02:00
/// Removes a session from the update list.
2018-06-20 16:49:13 -04:00
/// </summary>
2020-07-17 11:03:07 +02:00
/// <param name="session">The session to remove</param>
2018-06-20 16:49:13 -04:00
public void UnsubscribeSession ( IPlayerSession session )
{
2020-07-17 11:03:07 +02:00
if ( SubscribedSessions . Contains ( session ) )
2018-10-25 17:35:34 -07:00
{
2021-12-05 18:09:01 +01:00
Logger . DebugS ( LoggerName , $"Storage (UID {Owner}) unsubscribed player session (UID {session.AttachedEntity})." ) ;
2020-07-17 11:03:07 +02:00
2018-10-25 17:35:34 -07:00
SubscribedSessions . Remove ( session ) ;
2021-10-27 18:10:40 +02:00
#pragma warning disable 618
2018-10-25 17:35:34 -07:00
SendNetworkMessage ( new CloseStorageUIMessage ( ) , session . ConnectedClient ) ;
2021-10-27 18:10:40 +02:00
#pragma warning restore 618
2018-10-25 17:35:34 -07:00
}
2021-11-27 19:43:19 +13:00
2021-11-29 12:25:22 +13:00
CloseNestedInterfaces ( session ) ;
2021-11-27 19:43:19 +13:00
if ( SubscribedSessions . Count = = 0 )
UpdateStorageVisualization ( ) ;
2018-10-25 17:35:34 -07:00
}
2021-11-29 12:25:22 +13:00
/// <summary>
/// If the user has nested-UIs open (e.g., PDA UI open when pda is in a backpack), close them.
/// </summary>
/// <param name="session"></param>
public void CloseNestedInterfaces ( IPlayerSession session )
{
if ( StoredEntities = = null )
return ;
foreach ( var entity in StoredEntities )
{
2021-12-03 15:53:09 +01:00
if ( _entityManager . TryGetComponent ( entity , out ServerStorageComponent storageComponent ) )
2021-11-29 12:25:22 +13:00
{
2021-12-07 21:54:00 +11:00
DebugTools . Assert ( storageComponent ! = this , $"Storage component contains itself!? Entity: {Owner}" ) ;
2021-11-29 12:25:22 +13:00
storageComponent . UnsubscribeSession ( session ) ;
}
2021-12-03 15:53:09 +01:00
if ( _entityManager . TryGetComponent ( entity , out ServerUserInterfaceComponent uiComponent ) )
2021-11-29 12:25:22 +13:00
{
foreach ( var ui in uiComponent . Interfaces )
{
ui . Close ( session ) ;
}
}
}
}
2020-07-17 11:03:07 +02:00
private void HandlePlayerSessionChangeEvent ( object? obj , SessionStatusEventArgs sessionStatus )
{
2021-12-05 18:09:01 +01:00
Logger . DebugS ( LoggerName , $"Storage (UID {Owner}) handled a status change in player session (UID {sessionStatus.Session.AttachedEntity})." ) ;
2020-07-17 11:03:07 +02:00
if ( sessionStatus . NewStatus ! = SessionStatus . InGame )
{
UnsubscribeSession ( sessionStatus . Session ) ;
}
}
2021-06-19 19:41:26 -07:00
protected override void Initialize ( )
2018-06-20 16:49:13 -04:00
{
2020-07-17 11:03:07 +02:00
base . Initialize ( ) ;
// ReSharper disable once StringLiteralTypo
2021-11-29 12:25:22 +13:00
Storage = Owner . EnsureContainer < Container > ( "storagebase" ) ;
Storage . OccludesLight = _occludesLight ;
2021-11-27 19:43:19 +13:00
UpdateStorageVisualization ( ) ;
2022-01-31 01:53:31 +11:00
EnsureInitialCalculated ( ) ;
2018-06-20 16:49:13 -04:00
}
2021-10-27 18:10:40 +02:00
[Obsolete("Component Messages are deprecated, use Entity Events instead.")]
2020-07-17 11:03:07 +02:00
public override void HandleNetworkMessage ( ComponentMessage message , INetChannel channel , ICommonSession ? session = null )
2018-04-22 06:11:38 -05:00
{
2020-04-20 10:36:02 +01:00
base . HandleNetworkMessage ( message , channel , session ) ;
if ( session = = null )
{
throw new ArgumentException ( nameof ( session ) ) ;
}
2018-04-22 06:11:38 -05:00
switch ( message )
{
2020-07-17 11:03:07 +02:00
case RemoveEntityMessage remove :
2021-08-10 16:18:57 -07:00
{
EnsureInitialCalculated ( ) ;
2020-07-17 11:03:07 +02:00
2021-12-05 21:02:04 +01:00
if ( session . AttachedEntity is not { Valid : true } player )
2021-08-10 16:18:57 -07:00
{
break ;
}
2018-04-22 06:11:38 -05:00
2021-12-05 18:09:01 +01:00
var ownerTransform = _entityManager . GetComponent < TransformComponent > ( Owner ) ;
var playerTransform = _entityManager . GetComponent < TransformComponent > ( player ) ;
2020-07-17 11:03:07 +02:00
2021-12-05 18:09:01 +01:00
if ( ! playerTransform . Coordinates . InRange ( _entityManager , ownerTransform . Coordinates , 2 ) | |
2021-09-20 08:40:22 +02:00
Owner . IsInContainer ( ) & & ! playerTransform . ContainsEntity ( ownerTransform ) )
2021-08-10 16:18:57 -07:00
{
break ;
}
2021-07-31 19:52:33 +02:00
2021-12-05 18:09:01 +01:00
if ( ! remove . EntityUid . Valid | | Storage ? . Contains ( remove . EntityUid ) = = false )
2021-08-10 16:18:57 -07:00
{
break ;
}
2018-04-22 06:11:38 -05:00
2021-12-30 22:56:10 +01:00
if ( ! _entityManager . TryGetComponent ( remove . EntityUid , out SharedItemComponent ? item ) | | ! _entityManager . TryGetComponent ( player , out HandsComponent ? hands ) )
2021-08-10 16:18:57 -07:00
{
2020-07-17 11:03:07 +02:00
break ;
2018-04-22 06:11:38 -05:00
}
2021-08-10 16:18:57 -07:00
if ( ! hands . CanPutInHand ( item ) )
2021-07-31 19:52:33 +02:00
{
2021-08-10 16:18:57 -07:00
break ;
}
2020-07-17 11:03:07 +02:00
2021-08-10 16:18:57 -07:00
hands . PutInHand ( item ) ;
2020-07-17 11:03:07 +02:00
2021-08-10 16:18:57 -07:00
break ;
}
case InsertEntityMessage _ :
{
EnsureInitialCalculated ( ) ;
2020-07-17 11:03:07 +02:00
2021-12-05 21:02:04 +01:00
if ( session . AttachedEntity is not { Valid : true } player )
2021-08-10 16:18:57 -07:00
{
break ;
}
2020-02-17 01:19:35 +02:00
2021-08-10 16:18:57 -07:00
if ( ! player . InRangeUnobstructed ( Owner , popup : true ) )
{
2020-07-17 11:03:07 +02:00
break ;
}
2021-08-10 16:18:57 -07:00
PlayerInsertHeldEntity ( player ) ;
break ;
}
2018-10-25 17:35:34 -07:00
case CloseStorageUIMessage _ :
2021-08-10 16:18:57 -07:00
{
if ( session is not IPlayerSession playerSession )
2020-07-17 11:03:07 +02:00
{
break ;
}
2021-08-10 16:18:57 -07:00
UnsubscribeSession ( playerSession ) ;
break ;
}
2018-04-22 06:11:38 -05:00
}
}
2018-08-22 01:19:47 -07:00
2020-07-17 11:03:07 +02:00
/// <summary>
/// Inserts storable entities into this storage container if possible, otherwise return to the hand of the user
/// </summary>
/// <param name="eventArgs"></param>
/// <returns>true if inserted, false otherwise</returns>
2020-08-18 14:39:08 +02:00
async Task < bool > IInteractUsing . InteractUsing ( InteractUsingEventArgs eventArgs )
2018-08-22 01:19:47 -07:00
{
2021-11-03 14:33:36 -07:00
if ( ! _clickInsert )
return false ;
2021-12-03 15:53:09 +01:00
Logger . DebugS ( LoggerName , $"Storage (UID {Owner}) attacked by user (UID {eventArgs.User}) with entity (UID {eventArgs.Using})." ) ;
2018-11-11 20:04:52 +01:00
2021-12-05 18:09:01 +01:00
if ( _entityManager . HasComponent < PlaceableSurfaceComponent > ( Owner ) )
2018-11-11 20:04:52 +01:00
{
2020-07-17 11:03:07 +02:00
return false ;
2018-11-11 20:04:52 +01:00
}
2021-02-03 22:07:13 +00:00
return PlayerInsertHeldEntity ( eventArgs . User ) ;
2020-07-17 11:03:07 +02:00
}
2019-05-05 13:09:21 +02:00
2020-07-17 11:03:07 +02:00
/// <summary>
/// Sends a message to open the storage UI
/// </summary>
/// <param name="eventArgs"></param>
/// <returns></returns>
2022-01-05 02:23:01 +13:00
void IActivate . Activate ( ActivateEventArgs eventArgs )
2020-07-17 11:03:07 +02:00
{
EnsureInitialCalculated ( ) ;
OpenStorageUI ( eventArgs . User ) ;
2018-11-11 20:04:52 +01:00
}
2019-06-07 16:15:20 +05:00
2021-02-03 22:07:13 +00:00
/// <summary>
/// Allows a user to pick up entities by clicking them, or pick up all entities in a certain radius
/// arround a click.
/// </summary>
/// <param name="eventArgs"></param>
/// <returns></returns>
async Task < bool > IAfterInteract . AfterInteract ( AfterInteractEventArgs eventArgs )
{
2022-02-05 15:39:01 +13:00
if ( ! eventArgs . CanReach ) return false ;
2021-02-03 22:07:13 +00:00
// Pick up all entities in a radius around the clicked location.
// The last half of the if is because carpets exist and this is terrible
2021-12-05 21:02:04 +01:00
if ( _areaInsert & & ( eventArgs . Target = = null | | ! _entityManager . HasComponent < SharedItemComponent > ( eventArgs . Target . Value ) ) )
2021-02-03 22:07:13 +00:00
{
2021-12-05 18:09:01 +01:00
var validStorables = new List < EntityUid > ( ) ;
2021-10-27 14:12:36 +07:00
foreach ( var entity in IoCManager . Resolve < IEntityLookup > ( ) . GetEntitiesInRange ( eventArgs . ClickLocation , _areaInsertRadius , LookupFlags . None ) )
2021-02-03 22:07:13 +00:00
{
2021-09-20 08:40:22 +02:00
if ( entity . IsInContainer ( )
2021-02-03 22:07:13 +00:00
| | entity = = eventArgs . User
2021-12-05 18:09:01 +01:00
| | ! _entityManager . HasComponent < SharedItemComponent > ( entity )
2021-10-31 14:23:26 +01:00
| | ! EntitySystem . Get < InteractionSystem > ( ) . InRangeUnobstructed ( eventArgs . User , entity ) )
2021-02-03 22:07:13 +00:00
continue ;
validStorables . Add ( entity ) ;
}
//If there's only one then let's be generous
if ( validStorables . Count > 1 )
{
var doAfterSystem = EntitySystem . Get < DoAfterSystem > ( ) ;
var doAfterArgs = new DoAfterEventArgs ( eventArgs . User , 0.2f * validStorables . Count , CancellationToken . None , Owner )
{
BreakOnStun = true ,
BreakOnDamage = true ,
BreakOnUserMove = true ,
NeedHand = true ,
} ;
2021-07-04 13:32:24 +02:00
var result = await doAfterSystem . WaitDoAfter ( doAfterArgs ) ;
2021-02-03 22:07:13 +00:00
if ( result ! = DoAfterStatus . Finished ) return true ;
}
var successfullyInserted = new List < EntityUid > ( ) ;
var successfullyInsertedPositions = new List < EntityCoordinates > ( ) ;
foreach ( var entity in validStorables )
{
// Check again, situation may have changed for some entities, but we'll still pick up any that are valid
2021-09-20 08:40:22 +02:00
if ( entity . IsInContainer ( )
2021-02-03 22:07:13 +00:00
| | entity = = eventArgs . User
2021-12-05 18:09:01 +01:00
| | ! _entityManager . HasComponent < SharedItemComponent > ( entity ) )
2021-02-03 22:07:13 +00:00
continue ;
2021-12-05 18:09:01 +01:00
var position = EntityCoordinates . FromMap ( _entityManager . GetComponent < TransformComponent > ( Owner ) . Parent ? . Owner ? ? Owner , _entityManager . GetComponent < TransformComponent > ( entity ) . MapPosition ) ;
2021-02-03 22:07:13 +00:00
if ( PlayerInsertEntityInWorld ( eventArgs . User , entity ) )
{
2021-12-03 15:53:09 +01:00
successfullyInserted . Add ( entity ) ;
2021-10-20 13:25:22 +00:00
successfullyInsertedPositions . Add ( position ) ;
2021-02-03 22:07:13 +00:00
}
}
// If we picked up atleast one thing, play a sound and do a cool animation!
2021-07-31 19:52:33 +02:00
if ( successfullyInserted . Count > 0 )
2021-02-03 22:07:13 +00:00
{
2021-07-10 17:35:33 +02:00
PlaySoundCollection ( ) ;
2021-10-27 18:10:40 +02:00
#pragma warning disable 618
2021-02-03 22:07:13 +00:00
SendNetworkMessage (
2021-10-27 18:10:40 +02:00
#pragma warning restore 618
2021-02-03 22:07:13 +00:00
new AnimateInsertingEntitiesMessage (
successfullyInserted ,
successfullyInsertedPositions
)
) ;
}
return true ;
}
// Pick up the clicked entity
2021-07-31 19:52:33 +02:00
else if ( _quickInsert )
2021-02-03 22:07:13 +00:00
{
2021-12-05 18:09:01 +01:00
if ( eventArgs . Target is not { Valid : true } target )
{
return false ;
}
if ( target . IsInContainer ( )
| | target = = eventArgs . User
| | ! _entityManager . HasComponent < SharedItemComponent > ( target ) )
2021-02-03 22:07:13 +00:00
return false ;
2021-12-05 18:09:01 +01:00
var position = EntityCoordinates . FromMap (
_entityManager . GetComponent < TransformComponent > ( Owner ) . Parent ? . Owner ? ? Owner ,
_entityManager . GetComponent < TransformComponent > ( target ) . MapPosition ) ;
if ( PlayerInsertEntityInWorld ( eventArgs . User , target ) )
2021-02-03 22:07:13 +00:00
{
2021-10-27 18:10:40 +02:00
#pragma warning disable 618
2021-02-03 22:07:13 +00:00
SendNetworkMessage ( new AnimateInsertingEntitiesMessage (
2021-10-27 18:10:40 +02:00
#pragma warning restore 618
2021-12-05 18:09:01 +01:00
new List < EntityUid > { target } ,
new List < EntityCoordinates > { position }
2021-02-03 22:07:13 +00:00
) ) ;
return true ;
}
return true ;
}
return false ;
}
2019-06-07 16:15:20 +05:00
void IDestroyAct . OnDestroy ( DestructionEventArgs eventArgs )
{
2020-07-17 11:03:07 +02:00
var storedEntities = StoredEntities ? . ToList ( ) ;
if ( storedEntities = = null )
{
return ;
}
2019-06-07 16:15:20 +05:00
foreach ( var entity in storedEntities )
{
Remove ( entity ) ;
}
}
2020-02-17 01:19:35 +02:00
2020-06-21 21:57:22 +02:00
void IExAct . OnExplosion ( ExplosionEventArgs eventArgs )
{
if ( eventArgs . Severity < ExplosionSeverity . Heavy )
{
return ;
}
2020-07-17 11:03:07 +02:00
var storedEntities = StoredEntities ? . ToList ( ) ;
if ( storedEntities = = null )
{
return ;
}
2020-06-21 21:57:22 +02:00
foreach ( var entity in storedEntities )
{
2021-12-05 18:09:01 +01:00
var exActs = _entityManager . GetComponents < IExAct > ( entity ) . ToArray ( ) ;
2020-06-21 21:57:22 +02:00
foreach ( var exAct in exActs )
{
exAct . OnExplosion ( eventArgs ) ;
}
}
}
2021-01-05 05:34:53 +00:00
2021-07-10 17:35:33 +02:00
private void PlaySoundCollection ( )
2021-01-05 05:34:53 +00:00
{
2021-07-31 19:52:33 +02:00
SoundSystem . Play ( Filter . Pvs ( Owner ) , StorageSoundCollection . GetSound ( ) , Owner , AudioParams . Default ) ;
2021-01-05 05:34:53 +00:00
}
2018-04-22 06:11:38 -05:00
}
}