2023-09-11 09:42:41 +10:00
using System.Diagnostics.CodeAnalysis ;
using System.Linq ;
using Content.Server.DeviceNetwork.Systems ;
using Content.Server.PDA ;
2022-11-08 21:00:20 +01:00
using Content.Shared.CartridgeLoader ;
using Content.Shared.Interaction ;
using Robust.Server.Containers ;
using Robust.Server.GameObjects ;
using Robust.Shared.Containers ;
using Robust.Shared.Map ;
2023-10-28 09:59:53 +11:00
using Robust.Shared.Player ;
2022-11-08 21:00:20 +01:00
namespace Content.Server.CartridgeLoader ;
public sealed class CartridgeLoaderSystem : SharedCartridgeLoaderSystem
{
[Dependency] private readonly ContainerSystem _containerSystem = default ! ;
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default ! ;
2023-09-11 09:42:41 +10:00
[Dependency] private readonly PdaSystem _pda = default ! ;
2022-11-08 21:00:20 +01:00
public override void Initialize ( )
{
base . Initialize ( ) ;
SubscribeLocalEvent < CartridgeLoaderComponent , MapInitEvent > ( OnMapInit ) ;
SubscribeLocalEvent < CartridgeLoaderComponent , DeviceNetworkPacketEvent > ( OnPacketReceived ) ;
SubscribeLocalEvent < CartridgeLoaderComponent , AfterInteractEvent > ( OnUsed ) ;
SubscribeLocalEvent < CartridgeLoaderComponent , CartridgeLoaderUiMessage > ( OnLoaderUiMessage ) ;
SubscribeLocalEvent < CartridgeLoaderComponent , CartridgeUiMessage > ( OnUiMessage ) ;
}
2023-09-11 09:42:41 +10:00
public IReadOnlyList < EntityUid > GetInstalled ( EntityUid uid , ContainerManagerComponent ? comp = null )
{
if ( _containerSystem . TryGetContainer ( uid , InstalledContainerId , out var container , comp ) )
return container . ContainedEntities ;
return Array . Empty < EntityUid > ( ) ;
}
public bool TryGetProgram < T > (
EntityUid uid ,
[NotNullWhen(true)] out EntityUid ? programUid ,
[NotNullWhen(true)] out T ? program ,
bool installedOnly = false ,
CartridgeLoaderComponent ? loader = null ,
2023-09-20 10:12:48 +10:00
ContainerManagerComponent ? containerManager = null ) where T : IComponent
2023-09-11 09:42:41 +10:00
{
program = default ;
programUid = null ;
if ( ! _containerSystem . TryGetContainer ( uid , InstalledContainerId , out var container , containerManager ) )
return false ;
foreach ( var prog in container . ContainedEntities )
{
if ( ! TryComp ( prog , out program ) )
continue ;
programUid = prog ;
return true ;
}
if ( installedOnly )
return false ;
if ( ! Resolve ( uid , ref loader ) | | ! TryComp ( loader . CartridgeSlot . Item , out program ) )
return false ;
programUid = loader . CartridgeSlot . Item ;
return true ;
}
public bool TryGetProgram < T > (
EntityUid uid ,
[NotNullWhen(true)] out EntityUid ? programUid ,
bool installedOnly = false ,
CartridgeLoaderComponent ? loader = null ,
2023-09-20 10:12:48 +10:00
ContainerManagerComponent ? containerManager = null ) where T : IComponent
2023-09-11 09:42:41 +10:00
{
return TryGetProgram < T > ( uid , out programUid , out _ , installedOnly , loader , containerManager ) ;
}
public bool HasProgram < T > (
EntityUid uid ,
bool installedOnly = false ,
CartridgeLoaderComponent ? loader = null ,
2023-09-20 10:12:48 +10:00
ContainerManagerComponent ? containerManager = null ) where T : IComponent
2023-09-11 09:42:41 +10:00
{
return TryGetProgram < T > ( uid , out _ , out _ , installedOnly , loader , containerManager ) ;
}
2022-11-08 21:00:20 +01:00
/// <summary>
/// Updates the cartridge loaders ui state.
/// </summary>
/// <remarks>
/// Because the cartridge loader integrates with the ui of the entity using it, the entities ui state needs to inherit from <see cref="CartridgeLoaderUiState"/>
/// and use this method to update its state so the cartridge loaders state can be added to it.
/// </remarks>
2023-06-15 03:44:28 +02:00
/// <seealso cref="PDA.PdaSystem.UpdatePdaUserInterface"/>
2023-10-28 09:59:53 +11:00
public void UpdateUiState ( EntityUid loaderUid , ICommonSession ? session , CartridgeLoaderComponent ? loader )
2022-11-08 21:00:20 +01:00
{
if ( ! Resolve ( loaderUid , ref loader ) )
return ;
2023-09-11 09:42:41 +10:00
if ( ! _userInterfaceSystem . TryGetUi ( loaderUid , loader . UiKey , out var ui ) )
return ;
2022-11-08 21:00:20 +01:00
2023-09-11 09:42:41 +10:00
var programs = GetAvailablePrograms ( loaderUid , loader ) ;
var state = new CartridgeLoaderUiState ( programs , GetNetEntity ( loader . ActiveProgram ) ) ;
_userInterfaceSystem . SetUiState ( ui , state , session ) ;
2022-11-08 21:00:20 +01:00
}
/// <summary>
/// Updates the programs ui state
/// </summary>
/// <param name="loaderUid">The cartridge loaders entity uid</param>
/// <param name="state">The programs ui state. Programs should use their own ui state class inheriting from <see cref="BoundUserInterfaceState"/></param>
/// <param name="session">The players session</param>
/// <param name="loader">The cartridge loader component</param>
/// <remarks>
/// This method is called "UpdateCartridgeUiState" but cartridges and a programs are the same. A cartridge is just a program as a visible item.
/// </remarks>
/// <seealso cref="Cartridges.NotekeeperCartridgeSystem.UpdateUiState"/>
2023-10-28 09:59:53 +11:00
public void UpdateCartridgeUiState ( EntityUid loaderUid , BoundUserInterfaceState state , ICommonSession ? session = default ! , CartridgeLoaderComponent ? loader = default ! )
2022-11-08 21:00:20 +01:00
{
if ( ! Resolve ( loaderUid , ref loader ) )
return ;
2023-07-08 09:02:17 -07:00
if ( _userInterfaceSystem . TryGetUi ( loaderUid , loader . UiKey , out var ui ) )
2023-09-11 09:42:41 +10:00
_userInterfaceSystem . SetUiState ( ui , state , session ) ;
2022-11-08 21:00:20 +01:00
}
/// <summary>
/// Returns a list of all installed programs and the inserted cartridge if it isn't already installed
/// </summary>
/// <param name="uid">The cartridge loaders uid</param>
/// <param name="loader">The cartridge loader component</param>
/// <returns>A list of all the available program entity ids</returns>
2023-09-11 09:42:41 +10:00
public List < NetEntity > GetAvailablePrograms ( EntityUid uid , CartridgeLoaderComponent ? loader = default ! )
2022-11-08 21:00:20 +01:00
{
if ( ! Resolve ( uid , ref loader ) )
2023-09-11 09:42:41 +10:00
return new List < NetEntity > ( ) ;
2022-11-08 21:00:20 +01:00
2023-09-11 09:42:41 +10:00
var available = GetNetEntityList ( GetInstalled ( uid ) ) ;
2022-11-08 21:00:20 +01:00
2023-09-11 09:42:41 +10:00
if ( loader . CartridgeSlot . Item is not { } cartridge )
return available ;
2022-11-08 21:00:20 +01:00
2023-09-11 09:42:41 +10:00
// TODO exclude duplicate programs. Or something I dunno I CBF fixing this mess.
available . Add ( GetNetEntity ( cartridge ) ) ;
2022-11-08 21:00:20 +01:00
return available ;
}
/// <summary>
/// Installs a cartridge by spawning an invisible version of the cartridges prototype into the cartridge loaders program container program container
/// </summary>
/// <param name="loaderUid">The cartridge loader uid</param>
/// <param name="cartridgeUid">The uid of the cartridge to be installed</param>
/// <param name="loader">The cartridge loader component</param>
/// <returns>Whether installing the cartridge was successful</returns>
public bool InstallCartridge ( EntityUid loaderUid , EntityUid cartridgeUid , CartridgeLoaderComponent ? loader = default ! )
{
2023-09-11 09:42:41 +10:00
if ( ! Resolve ( loaderUid , ref loader ) )
2022-11-08 21:00:20 +01:00
return false ;
//This will eventually be replaced by serializing and deserializing the cartridge to copy it when something needs
//the data on the cartridge to carry over when installing
2023-09-11 09:42:41 +10:00
// For anyone stumbling onto this: Do not do this or I will cut you.
2022-11-08 21:00:20 +01:00
var prototypeId = Prototype ( cartridgeUid ) ? . ID ;
2022-11-10 01:59:16 +01:00
return prototypeId ! = null & & InstallProgram ( loaderUid , prototypeId , loader : loader ) ;
2022-11-08 21:00:20 +01:00
}
/// <summary>
/// Installs a program by its prototype
/// </summary>
/// <param name="loaderUid">The cartridge loader uid</param>
/// <param name="prototype">The prototype name</param>
2022-11-10 01:59:16 +01:00
/// <param name="deinstallable">Whether the program can be deinstalled or not</param>
2022-11-08 21:00:20 +01:00
/// <param name="loader">The cartridge loader component</param>
/// <returns>Whether installing the cartridge was successful</returns>
2023-07-08 09:02:17 -07:00
public bool InstallProgram ( EntityUid loaderUid , string prototype , bool deinstallable = true , CartridgeLoaderComponent ? loader = default ! )
2022-11-08 21:00:20 +01:00
{
2023-09-11 09:42:41 +10:00
if ( ! Resolve ( loaderUid , ref loader ) )
2022-11-08 21:00:20 +01:00
return false ;
2023-09-11 09:42:41 +10:00
if ( ! _containerSystem . TryGetContainer ( loaderUid , InstalledContainerId , out var container ) )
2022-11-08 21:00:20 +01:00
return false ;
2023-09-11 09:42:41 +10:00
if ( container . Count > = loader . DiskSpace )
2023-08-05 13:37:08 +05:00
return false ;
2023-09-11 09:42:41 +10:00
// TODO cancel duplicate program installations
2023-08-05 13:37:08 +05:00
var ev = new ProgramInstallationAttempt ( loaderUid , prototype ) ;
RaiseLocalEvent ( ref ev ) ;
if ( ev . Cancelled )
2022-11-08 21:00:20 +01:00
return false ;
var installedProgram = Spawn ( prototype , new EntityCoordinates ( loaderUid , 0 , 0 ) ) ;
2024-02-27 02:38:00 +01:00
if ( ! TryComp ( installedProgram , out CartridgeComponent ? cartridge ) )
return false ;
2023-12-27 21:30:03 -08:00
_containerSystem . Insert ( installedProgram , container ) ;
2022-11-08 21:00:20 +01:00
2024-02-27 02:38:00 +01:00
UpdateCartridgeInstallationStatus ( installedProgram , deinstallable ? InstallationStatus . Installed : InstallationStatus . Readonly , cartridge ) ;
cartridge . LoaderUid = loaderUid ;
2022-11-08 21:00:20 +01:00
RaiseLocalEvent ( installedProgram , new CartridgeAddedEvent ( loaderUid ) ) ;
UpdateUserInterfaceState ( loaderUid , loader ) ;
return true ;
}
/// <summary>
/// Uninstalls a program using its uid
/// </summary>
/// <param name="loaderUid">The cartridge loader uid</param>
/// <param name="programUid">The uid of the program to be uninstalled</param>
/// <param name="loader">The cartridge loader component</param>
/// <returns>Whether uninstalling the program was successful</returns>
2023-07-08 09:02:17 -07:00
public bool UninstallProgram ( EntityUid loaderUid , EntityUid programUid , CartridgeLoaderComponent ? loader = default ! )
2022-11-08 21:00:20 +01:00
{
2023-09-11 09:42:41 +10:00
if ( ! Resolve ( loaderUid , ref loader ) )
return false ;
if ( ! GetInstalled ( loaderUid ) . Contains ( programUid ) )
2022-11-08 21:00:20 +01:00
return false ;
2024-02-27 02:38:00 +01:00
if ( TryComp ( programUid , out CartridgeComponent ? cartridge ) )
cartridge . LoaderUid = null ;
2022-11-08 21:00:20 +01:00
if ( loader . ActiveProgram = = programUid )
loader . ActiveProgram = null ;
loader . BackgroundPrograms . Remove ( programUid ) ;
2024-02-27 02:38:00 +01:00
QueueDel ( programUid ) ;
2022-11-08 21:00:20 +01:00
UpdateUserInterfaceState ( loaderUid , loader ) ;
return true ;
}
/// <summary>
/// Activates a program or cartridge and displays its ui fragment. Deactivates any previously active program.
/// </summary>
2023-07-08 09:02:17 -07:00
public void ActivateProgram ( EntityUid loaderUid , EntityUid programUid , CartridgeLoaderComponent ? loader = default ! )
2022-11-08 21:00:20 +01:00
{
if ( ! Resolve ( loaderUid , ref loader ) )
return ;
2023-09-11 09:42:41 +10:00
if ( ! HasProgram ( loaderUid , programUid , loader ) )
2022-11-08 21:00:20 +01:00
return ;
if ( loader . ActiveProgram . HasValue )
DeactivateProgram ( loaderUid , programUid , loader ) ;
if ( ! loader . BackgroundPrograms . Contains ( programUid ) )
RaiseLocalEvent ( programUid , new CartridgeActivatedEvent ( loaderUid ) ) ;
loader . ActiveProgram = programUid ;
UpdateUserInterfaceState ( loaderUid , loader ) ;
}
/// <summary>
/// Deactivates the currently active program or cartridge.
/// </summary>
2023-07-08 09:02:17 -07:00
public void DeactivateProgram ( EntityUid loaderUid , EntityUid programUid , CartridgeLoaderComponent ? loader = default ! )
2022-11-08 21:00:20 +01:00
{
if ( ! Resolve ( loaderUid , ref loader ) )
return ;
2023-09-11 09:42:41 +10:00
if ( ! HasProgram ( loaderUid , programUid , loader ) | | loader . ActiveProgram ! = programUid )
2022-11-08 21:00:20 +01:00
return ;
if ( ! loader . BackgroundPrograms . Contains ( programUid ) )
RaiseLocalEvent ( programUid , new CartridgeDeactivatedEvent ( programUid ) ) ;
loader . ActiveProgram = default ;
UpdateUserInterfaceState ( loaderUid , loader ) ;
}
/// <summary>
/// Registers the given program as a running in the background. Programs running in the background will receive certain events like device net packets but not ui messages
/// </summary>
/// <remarks>
/// Programs wanting to use this functionality will have to provide a way to register and unregister themselves as background programs through their ui fragment.
/// </remarks>
2023-07-08 09:02:17 -07:00
public void RegisterBackgroundProgram ( EntityUid loaderUid , EntityUid cartridgeUid , CartridgeLoaderComponent ? loader = default ! )
2022-11-08 21:00:20 +01:00
{
if ( ! Resolve ( loaderUid , ref loader ) )
return ;
2023-09-11 09:42:41 +10:00
if ( ! HasProgram ( loaderUid , cartridgeUid , loader ) )
2022-11-08 21:00:20 +01:00
return ;
if ( loader . ActiveProgram ! = cartridgeUid )
RaiseLocalEvent ( cartridgeUid , new CartridgeActivatedEvent ( loaderUid ) ) ;
loader . BackgroundPrograms . Add ( cartridgeUid ) ;
}
/// <summary>
/// Unregisters the given program as running in the background
/// </summary>
2023-07-08 09:02:17 -07:00
public void UnregisterBackgroundProgram ( EntityUid loaderUid , EntityUid cartridgeUid , CartridgeLoaderComponent ? loader = default ! )
2022-11-08 21:00:20 +01:00
{
if ( ! Resolve ( loaderUid , ref loader ) )
return ;
2023-09-11 09:42:41 +10:00
if ( ! HasProgram ( loaderUid , cartridgeUid , loader ) )
2022-11-08 21:00:20 +01:00
return ;
if ( loader . ActiveProgram ! = cartridgeUid )
RaiseLocalEvent ( cartridgeUid , new CartridgeDeactivatedEvent ( loaderUid ) ) ;
loader . BackgroundPrograms . Remove ( cartridgeUid ) ;
}
2024-02-27 02:38:00 +01:00
public void SendNotification ( EntityUid loaderUid , string header , string message , CartridgeLoaderComponent ? loader = default ! )
{
if ( ! Resolve ( loaderUid , ref loader ) )
return ;
if ( ! loader . NotificationsEnabled )
return ;
var args = new CartridgeLoaderNotificationSentEvent ( header , message ) ;
RaiseLocalEvent ( loaderUid , ref args ) ;
}
2023-01-19 03:56:45 +01:00
protected override void OnItemInserted ( EntityUid uid , CartridgeLoaderComponent loader , EntInsertedIntoContainerMessage args )
2022-11-08 21:00:20 +01:00
{
2023-09-11 09:42:41 +10:00
if ( args . Container . ID ! = InstalledContainerId & & args . Container . ID ! = loader . CartridgeSlot . ID )
return ;
2022-11-08 21:00:20 +01:00
RaiseLocalEvent ( args . Entity , new CartridgeAddedEvent ( uid ) ) ;
base . OnItemInserted ( uid , loader , args ) ;
}
2023-01-19 03:56:45 +01:00
protected override void OnItemRemoved ( EntityUid uid , CartridgeLoaderComponent loader , EntRemovedFromContainerMessage args )
2022-11-08 21:00:20 +01:00
{
2023-09-11 09:42:41 +10:00
if ( args . Container . ID ! = InstalledContainerId & & args . Container . ID ! = loader . CartridgeSlot . ID )
return ;
2022-11-08 21:00:20 +01:00
var deactivate = loader . BackgroundPrograms . Remove ( args . Entity ) ;
if ( loader . ActiveProgram = = args . Entity )
{
loader . ActiveProgram = default ;
deactivate = true ;
}
if ( deactivate )
RaiseLocalEvent ( args . Entity , new CartridgeDeactivatedEvent ( uid ) ) ;
RaiseLocalEvent ( args . Entity , new CartridgeRemovedEvent ( uid ) ) ;
base . OnItemRemoved ( uid , loader , args ) ;
2023-09-11 09:42:41 +10:00
_pda . UpdatePdaUi ( uid ) ;
2022-11-08 21:00:20 +01:00
}
/// <summary>
/// Installs programs from the list of preinstalled programs
/// </summary>
private void OnMapInit ( EntityUid uid , CartridgeLoaderComponent component , MapInitEvent args )
{
2023-09-11 09:42:41 +10:00
// TODO remove this and use container fill.
2022-11-08 21:00:20 +01:00
foreach ( var prototype in component . PreinstalledPrograms )
{
2022-11-10 01:59:16 +01:00
InstallProgram ( uid , prototype , deinstallable : false ) ;
2022-11-08 21:00:20 +01:00
}
}
private void OnUsed ( EntityUid uid , CartridgeLoaderComponent component , AfterInteractEvent args )
{
RelayEvent ( component , new CartridgeAfterInteractEvent ( uid , args ) ) ;
}
private void OnPacketReceived ( EntityUid uid , CartridgeLoaderComponent component , DeviceNetworkPacketEvent args )
{
RelayEvent ( component , new CartridgeDeviceNetPacketEvent ( uid , args ) ) ;
}
private void OnLoaderUiMessage ( EntityUid loaderUid , CartridgeLoaderComponent component , CartridgeLoaderUiMessage message )
{
2023-09-11 09:42:41 +10:00
var cartridge = GetEntity ( message . CartridgeUid ) ;
2022-11-08 21:00:20 +01:00
switch ( message . Action )
{
case CartridgeUiMessageAction . Activate :
2023-09-11 09:42:41 +10:00
ActivateProgram ( loaderUid , cartridge , component ) ;
2022-11-08 21:00:20 +01:00
break ;
case CartridgeUiMessageAction . Deactivate :
2023-09-11 09:42:41 +10:00
DeactivateProgram ( loaderUid , cartridge , component ) ;
2022-11-08 21:00:20 +01:00
break ;
case CartridgeUiMessageAction . Install :
2023-09-11 09:42:41 +10:00
InstallCartridge ( loaderUid , cartridge , component ) ;
2022-11-08 21:00:20 +01:00
break ;
case CartridgeUiMessageAction . Uninstall :
2023-09-11 09:42:41 +10:00
UninstallProgram ( loaderUid , cartridge , component ) ;
2022-11-08 21:00:20 +01:00
break ;
case CartridgeUiMessageAction . UIReady :
if ( component . ActiveProgram . HasValue )
RaiseLocalEvent ( component . ActiveProgram . Value , new CartridgeUiReadyEvent ( loaderUid ) ) ;
break ;
default :
2023-07-08 09:02:17 -07:00
throw new ArgumentOutOfRangeException ( $"Unrecognized UI action passed from cartridge loader ui {message.Action}." ) ;
2022-11-08 21:00:20 +01:00
}
}
/// <summary>
/// Relays ui messages meant for cartridges to the currently active cartridge
/// </summary>
private void OnUiMessage ( EntityUid uid , CartridgeLoaderComponent component , CartridgeUiMessage args )
{
var cartridgeEvent = args . MessageEvent ;
2023-09-11 09:42:41 +10:00
cartridgeEvent . LoaderUid = GetNetEntity ( uid ) ;
2022-11-08 21:00:20 +01:00
RelayEvent ( component , cartridgeEvent , true ) ;
}
/// <summary>
/// Relays events to the currently active program and and programs running in the background.
/// Skips background programs if "skipBackgroundPrograms" is set to true
/// </summary>
/// <param name="loader">The cartritge loader component</param>
/// <param name="args">The event to be relayed</param>
/// <param name="skipBackgroundPrograms">Whether to skip relaying the event to programs running in the background</param>
private void RelayEvent < TEvent > ( CartridgeLoaderComponent loader , TEvent args , bool skipBackgroundPrograms = false ) where TEvent : notnull
{
if ( loader . ActiveProgram . HasValue )
RaiseLocalEvent ( loader . ActiveProgram . Value , args ) ;
if ( skipBackgroundPrograms )
return ;
foreach ( var program in loader . BackgroundPrograms )
{
//Prevent programs registered as running in the background receiving events twice if they are active
if ( loader . ActiveProgram . HasValue & & loader . ActiveProgram . Value . Equals ( program ) )
continue ;
RaiseLocalEvent ( program , args ) ;
}
}
/// <summary>
/// Shortcut for updating the loaders user interface state without passing in a subtype of <see cref="CartridgeLoaderUiState"/>
2023-06-15 03:44:28 +02:00
/// like the <see cref="PDA.PdaSystem"/> does when updating its ui state
2022-11-08 21:00:20 +01:00
/// </summary>
2023-06-15 03:44:28 +02:00
/// <seealso cref="PDA.PdaSystem.UpdatePdaUserInterface"/>
2022-11-08 21:00:20 +01:00
private void UpdateUserInterfaceState ( EntityUid loaderUid , CartridgeLoaderComponent loader )
{
2023-09-11 09:42:41 +10:00
UpdateUiState ( loaderUid , null , loader ) ;
2022-11-08 21:00:20 +01:00
}
2024-02-27 02:38:00 +01:00
private void UpdateCartridgeInstallationStatus ( EntityUid cartridgeUid , InstallationStatus installationStatus , CartridgeComponent cartridgeComponent )
2022-11-08 21:00:20 +01:00
{
2024-02-27 02:38:00 +01:00
cartridgeComponent . InstallationStatus = installationStatus ;
Dirty ( cartridgeUid , cartridgeComponent ) ;
2022-11-08 21:00:20 +01:00
}
2023-09-11 09:42:41 +10:00
private bool HasProgram ( EntityUid loader , EntityUid program , CartridgeLoaderComponent component )
2022-11-08 21:00:20 +01:00
{
2023-09-11 09:42:41 +10:00
return component . CartridgeSlot . Item = = program | | GetInstalled ( loader ) . Contains ( program ) ;
2022-11-08 21:00:20 +01:00
}
}
/// <summary>
/// Gets sent to running programs when the cartridge loader receives a device net package
/// </summary>
/// <seealso cref="DeviceNetworkPacketEvent"/>
public sealed class CartridgeDeviceNetPacketEvent : EntityEventArgs
{
public readonly EntityUid Loader ;
public readonly DeviceNetworkPacketEvent PacketEvent ;
public CartridgeDeviceNetPacketEvent ( EntityUid loader , DeviceNetworkPacketEvent packetEvent )
{
Loader = loader ;
PacketEvent = packetEvent ;
}
}
/// <summary>
/// Gets sent to running programs when the cartridge loader receives an after interact event
/// </summary>
/// <seealso cref="AfterInteractEvent"/>
public sealed class CartridgeAfterInteractEvent : EntityEventArgs
{
public readonly EntityUid Loader ;
public readonly AfterInteractEvent InteractEvent ;
public CartridgeAfterInteractEvent ( EntityUid loader , AfterInteractEvent interactEvent )
{
Loader = loader ;
InteractEvent = interactEvent ;
}
}
2023-08-05 13:37:08 +05:00
/// <summary>
/// Raised on an attempt of program installation.
/// </summary>
[ByRefEvent]
public record struct ProgramInstallationAttempt ( EntityUid LoaderUid , string Prototype , bool Cancelled = false ) ;