@@ -37,13 +37,16 @@ namespace Exiled.CustomRoles.API.Features
3737 /// </summary>
3838 public abstract class CustomRole
3939 {
40- private const float AddRoleDelay = 0.25f ;
40+ /// <summary>
41+ /// The delay after which ammo and items are added to the player.
42+ /// </summary>
43+ public const float AddRoleItemAndAmmoDelay = 0.25f ;
4144
42- private static Dictionary < Type , CustomRole ? > typeLookupTable = new ( ) ;
45+ private static readonly Dictionary < Type , CustomRole ? > TypeLookupTable = new ( ) ;
4346
44- private static Dictionary < string , CustomRole ? > stringLookupTable = new ( ) ;
47+ private static readonly Dictionary < string , CustomRole ? > StringLookupTable = new ( ) ;
4548
46- private static Dictionary < uint , CustomRole ? > idLookupTable = new ( ) ;
49+ private static readonly Dictionary < uint , CustomRole ? > IdLookupTable = new ( ) ;
4750
4851 /// <summary>
4952 /// Gets a list of all registered custom roles.
@@ -144,7 +147,7 @@ public abstract class CustomRole
144147 /// <summary>
145148 /// Gets or sets a value indicating broadcast that will be shown to the player.
146149 /// </summary>
147- public virtual Broadcast Broadcast { get ; set ; } = new Broadcast ( ) ;
150+ public virtual Broadcast ? Broadcast { get ; set ; } = new Broadcast ( ) ;
148151
149152 /// <summary>
150153 /// Gets or sets a value indicating whether players will receive a message for getting a custom item, when gaining it through the inventory config for this role.
@@ -183,9 +186,9 @@ public abstract class CustomRole
183186 /// <returns>The role, or <see langword="null"/> if it doesn't exist.</returns>
184187 public static CustomRole ? Get ( uint id )
185188 {
186- if ( ! idLookupTable . ContainsKey ( id ) )
187- idLookupTable . Add ( id , Registered ? . FirstOrDefault ( r => r . Id == id ) ) ;
188- return idLookupTable [ id ] ;
189+ if ( ! IdLookupTable . ContainsKey ( id ) )
190+ IdLookupTable . Add ( id , Registered ? . FirstOrDefault ( r => r . Id == id ) ) ;
191+ return IdLookupTable [ id ] ;
189192 }
190193
191194 /// <summary>
@@ -195,9 +198,9 @@ public abstract class CustomRole
195198 /// <returns>The role, or <see langword="null"/> if it doesn't exist.</returns>
196199 public static CustomRole ? Get ( Type t )
197200 {
198- if ( ! typeLookupTable . ContainsKey ( t ) )
199- typeLookupTable . Add ( t , Registered ? . FirstOrDefault ( r => r . GetType ( ) == t ) ) ;
200- return typeLookupTable [ t ] ;
201+ if ( ! TypeLookupTable . ContainsKey ( t ) )
202+ TypeLookupTable . Add ( t , Registered ? . FirstOrDefault ( r => r . GetType ( ) == t ) ) ;
203+ return TypeLookupTable [ t ] ;
201204 }
202205
203206 /// <summary>
@@ -207,9 +210,9 @@ public abstract class CustomRole
207210 /// <returns>The role, or <see langword="null"/> if it doesn't exist.</returns>
208211 public static CustomRole ? Get ( string name )
209212 {
210- if ( ! stringLookupTable . ContainsKey ( name ) )
211- stringLookupTable . Add ( name , Registered ? . FirstOrDefault ( r => r . Name == name ) ) ;
212- return stringLookupTable [ name ] ;
213+ if ( ! StringLookupTable . ContainsKey ( name ) )
214+ StringLookupTable . Add ( name , Registered ? . FirstOrDefault ( r => r . Name == name ) ) ;
215+ return StringLookupTable [ name ] ;
213216 }
214217
215218 /// <summary>
@@ -481,9 +484,9 @@ public static void ForceSyncSetPlayerFriendlyFire(CustomRole roleToSync, Player
481484 /// </summary>
482485 public virtual void Init ( )
483486 {
484- idLookupTable . Add ( Id , this ) ;
485- typeLookupTable . Add ( GetType ( ) , this ) ;
486- stringLookupTable . Add ( Name , this ) ;
487+ IdLookupTable . Add ( Id , this ) ;
488+ TypeLookupTable . Add ( GetType ( ) , this ) ;
489+ StringLookupTable . Add ( Name , this ) ;
487490 SubscribeEvents ( ) ;
488491 }
489492
@@ -492,68 +495,75 @@ public virtual void Init()
492495 /// </summary>
493496 public virtual void Destroy ( )
494497 {
495- idLookupTable . Remove ( Id ) ;
496- typeLookupTable . Remove ( GetType ( ) ) ;
497- stringLookupTable . Remove ( Name ) ;
498+ IdLookupTable . Remove ( Id ) ;
499+ TypeLookupTable . Remove ( GetType ( ) ) ;
500+ StringLookupTable . Remove ( Name ) ;
498501 UnsubscribeEvents ( ) ;
499502 }
500503
501504 /// <summary>
502505 /// Handles setup of the role, including spawn location, inventory and registering event handlers and add FF rules.
503506 /// </summary>
504507 /// <param name="player">The <see cref="Player"/> to add the role to.</param>
505- public virtual void AddRole ( Player player )
508+ public virtual void AddRole ( Player player ) => AddRole ( player , SpawnReason . ForceClass , false , RoleSpawnFlags . All ) ;
509+
510+ /// <summary>
511+ /// Handles setup of the role, including spawn location, inventory and registering event handlers and add FF rules.
512+ /// </summary>
513+ /// <param name="player">The <see cref="Player"/> to add the role to.</param>
514+ /// <param name="spawnReason">The <see cref="SpawnReason"/>.</param>
515+ /// <param name="overrideFlags">Whether it should use <paramref name="overrideSpawnFlags"/> or not.</param>
516+ /// <param name="overrideSpawnFlags">The <see cref="RoleSpawnFlags"/> to apply if <paramref name="overrideFlags"/> is <see langword="true"/>.</param>
517+ public virtual void AddRole ( Player player , SpawnReason spawnReason = SpawnReason . ForceClass , bool overrideFlags = false , RoleSpawnFlags overrideSpawnFlags = RoleSpawnFlags . All )
506518 {
507519 Log . Debug ( $ "{ Name } : Adding role to { player . Nickname } .") ;
508520 player . UniqueRole = Name ;
509521
510- if ( Role != RoleTypeId . None )
522+ RoleSpawnFlags keptSpawnFlags = overrideSpawnFlags ;
523+
524+ if ( Role == RoleTypeId . None )
511525 {
512- if ( KeepPositionOnSpawn )
513- {
514- if ( KeepInventoryOnSpawn )
515- player . Role . Set ( Role , SpawnReason . ForceClass , RoleSpawnFlags . None ) ;
516- else
517- player . Role . Set ( Role , SpawnReason . ForceClass , RoleSpawnFlags . AssignInventory ) ;
518- }
519- else
526+ keptSpawnFlags = RoleSpawnFlags . None ;
527+ }
528+ else
529+ {
530+ if ( ! overrideFlags )
520531 {
521- if ( KeepInventoryOnSpawn && player . IsAlive )
522- player . Role . Set ( Role , SpawnReason . ForceClass , RoleSpawnFlags . UseSpawnpoint ) ;
532+ if ( KeepPositionOnSpawn )
533+ keptSpawnFlags = KeepInventoryOnSpawn ? RoleSpawnFlags . None : RoleSpawnFlags . AssignInventory ;
523534 else
524- player . Role . Set ( Role , SpawnReason . ForceClass , RoleSpawnFlags . All ) ;
535+ keptSpawnFlags = KeepInventoryOnSpawn && player . IsAlive ? RoleSpawnFlags . UseSpawnpoint : RoleSpawnFlags . All ;
525536 }
537+
538+ player . Role . Set ( Role , spawnReason , keptSpawnFlags ) ;
526539 }
527540
528541 player . UniqueRole = Name ;
529542 TrackedPlayers . Add ( player ) ;
530543
531- Timing . CallDelayed (
532- AddRoleDelay ,
533- ( ) =>
534- {
535- if ( ! KeepInventoryOnSpawn )
544+ if ( keptSpawnFlags . HasFlag ( RoleSpawnFlags . AssignInventory ) )
545+ {
546+ Timing . CallDelayed (
547+ AddRoleItemAndAmmoDelay ,
548+ ( ) =>
536549 {
537550 Log . Debug ( $ "{ Name } : Clearing { player . Nickname } 's inventory.") ;
538551 player . ClearInventory ( ) ;
539- }
540552
541- foreach ( string itemName in Inventory )
542- {
543- Log . Debug ( $ "{ Name } : Adding { itemName } to inventory.") ;
544- TryAddItem ( player , itemName ) ;
545- }
553+ foreach ( string itemName in Inventory )
554+ {
555+ Log . Debug ( $ "{ Name } : Adding { itemName } to inventory.") ;
556+ TryAddItem ( player , itemName ) ;
557+ }
546558
547- if ( Ammo . Count > 0 )
548- {
549559 Log . Debug ( $ "{ Name } : Adding Ammo to { player . Nickname } inventory.") ;
550560 foreach ( AmmoType type in EnumUtils < AmmoType > . Values )
551561 {
552562 if ( type != AmmoType . None )
553563 player . SetAmmo ( type , Ammo . ContainsKey ( type ) ? Ammo [ type ] == ushort . MaxValue ? InventoryLimits . GetAmmoLimit ( type . GetItemType ( ) , player . ReferenceHub ) : Ammo [ type ] : ( ushort ) 0 ) ;
554564 }
555- }
556- } ) ;
565+ } ) ;
566+ }
557567
558568 Log . Debug ( $ "{ Name } : Setting health values.") ;
559569 player . Health = MaxHealth ;
@@ -563,9 +573,7 @@ public virtual void AddRole(Player player)
563573 fpcRole . Gravity = Gravity . Value ;
564574 Vector3 position = GetSpawnPosition ( ) ;
565575 if ( position != Vector3 . zero )
566- {
567576 player . Position = position ;
568- }
569577
570578 Log . Debug ( $ "{ Name } : Setting player info") ;
571579
@@ -580,7 +588,7 @@ public virtual void AddRole(Player player)
580588
581589 ShowMessage ( player ) ;
582590 ShowBroadcast ( player ) ;
583- RoleAdded ( player ) ;
591+ RoleAdded ( player , spawnReason , keptSpawnFlags ) ;
584592 player . TryAddCustomRoleFriendlyFire ( Name , CustomRoleFFMultiplier ) ;
585593
586594 if ( ! string . IsNullOrEmpty ( ConsoleMessage ) )
@@ -611,56 +619,49 @@ public virtual void AddRole(Player player)
611619 /// Removes the role from a specific player and FF rules.
612620 /// </summary>
613621 /// <param name="player">The <see cref="Player"/> to remove the role from.</param>
614- public virtual void RemoveRole ( Player player )
622+ public virtual void RemoveRole ( Player player ) => RemoveRole ( player , SpawnReason . ForceClass , RoleSpawnFlags . All ) ;
623+
624+ /// <summary>
625+ /// Removes the role from a specific player and FF rules.
626+ /// </summary>
627+ /// <param name="player">The <see cref="Player"/> to remove the role from.</param>
628+ /// <param name="spawnReason">The <see cref="SpawnReason"/>.</param>
629+ /// <param name="roleSpawnFlags">The <see cref="RoleSpawnFlags"/> to apply.</param>
630+ public virtual void RemoveRole ( Player player , SpawnReason spawnReason = SpawnReason . ForceClass , RoleSpawnFlags roleSpawnFlags = RoleSpawnFlags . All )
615631 {
616- if ( ! TrackedPlayers . Contains ( player ) )
632+ if ( ! TrackedPlayers . Remove ( player ) )
617633 return ;
634+
618635 Log . Debug ( $ "{ Name } : Removing role from { player . Nickname } ") ;
619- TrackedPlayers . Remove ( player ) ;
620636 player . CustomInfo = string . Empty ;
621637 player . InfoArea |= PlayerInfoArea . Role | PlayerInfoArea . Nickname ;
622638 player . Scale = Vector3 . one ;
623639 if ( CustomAbilities is not null )
624640 {
625641 foreach ( CustomAbility ability in CustomAbilities )
626- {
627642 ability . RemoveAbility ( player ) ;
628- }
629643 }
630644
631- RoleRemoved ( player ) ;
645+ RoleRemoved ( player , spawnReason , roleSpawnFlags ) ;
632646 player . UniqueRole = string . Empty ;
633647 player . TryRemoveCustomeRoleFriendlyFire ( Name ) ;
634648
635649 if ( RemovalKillsPlayer )
636- player . Role . Set ( RoleTypeId . Spectator ) ;
650+ player . Role . Set ( RoleTypeId . Spectator , spawnReason , roleSpawnFlags ) ;
637651 }
638652
639653 /// <summary>
640654 /// Tries to add <see cref="RoleTypeId"/> to CustomRole FriendlyFire rules.
641655 /// </summary>
642656 /// <param name="roleToAdd"> Role to add. </param>
643657 /// <param name="ffMult"> Friendly fire multiplier. </param>
644- public void SetFriendlyFire ( RoleTypeId roleToAdd , float ffMult )
645- {
646- if ( CustomRoleFFMultiplier . ContainsKey ( roleToAdd ) )
647- {
648- CustomRoleFFMultiplier [ roleToAdd ] = ffMult ;
649- }
650- else
651- {
652- CustomRoleFFMultiplier . Add ( roleToAdd , ffMult ) ;
653- }
654- }
658+ public void SetFriendlyFire ( RoleTypeId roleToAdd , float ffMult ) => CustomRoleFFMultiplier [ roleToAdd ] = ffMult ;
655659
656660 /// <summary>
657661 /// Wrapper to call <see cref="SetFriendlyFire(RoleTypeId, float)"/>.
658662 /// </summary>
659663 /// <param name="roleFF"> Role with FF to add even if it exists. </param>
660- public void SetFriendlyFire ( KeyValuePair < RoleTypeId , float > roleFF )
661- {
662- SetFriendlyFire ( roleFF . Key , roleFF . Value ) ;
663- }
664+ public void SetFriendlyFire ( KeyValuePair < RoleTypeId , float > roleFF ) => SetFriendlyFire ( roleFF . Key , roleFF . Value ) ;
664665
665666 /// <summary>
666667 /// Tries to add <see cref="RoleTypeId"/> to CustomRole FriendlyFire rules.
@@ -671,9 +672,7 @@ public void SetFriendlyFire(KeyValuePair<RoleTypeId, float> roleFF)
671672 public bool TryAddFriendlyFire ( RoleTypeId roleToAdd , float ffMult )
672673 {
673674 if ( CustomRoleFFMultiplier . ContainsKey ( roleToAdd ) )
674- {
675675 return false ;
676- }
677676
678677 CustomRoleFFMultiplier . Add ( roleToAdd , ffMult ) ;
679678 return true ;
@@ -719,9 +718,7 @@ public bool TryAddFriendlyFire(Dictionary<RoleTypeId, float> ffRules, bool overw
719718 if ( ! overwrite )
720719 {
721720 foreach ( KeyValuePair < RoleTypeId , float > roleFF in temporaryFriendlyFireRules )
722- {
723721 TryAddFriendlyFire ( roleFF ) ;
724- }
725722 }
726723
727724 DictionaryPool < RoleTypeId , float > . Pool . Return ( temporaryFriendlyFireRules ) ;
@@ -898,12 +895,30 @@ protected virtual void UnsubscribeEvents()
898895 /// Shows the spawn broadcast to the player.
899896 /// </summary>
900897 /// <param name="player">The <see cref="Player"/> to show the message to.</param>
901- protected virtual void ShowBroadcast ( Player player ) => player . Broadcast ( Broadcast ) ;
898+ protected virtual void ShowBroadcast ( Player player )
899+ {
900+ if ( Broadcast != null && Broadcast . Duration > 0 && ! string . IsNullOrEmpty ( Broadcast . Content ) )
901+ player . Broadcast ( Broadcast ) ;
902+ }
903+
904+ /// <summary>
905+ /// Called after the role has been added to the player.
906+ /// </summary>
907+ /// <param name="player">The <see cref="Player"/> the role was added to.</param>
908+ /// <param name="spawnReason">The <see cref="SpawnReason"/>.</param>
909+ /// <param name="roleSpawnFlags">The <see cref="RoleSpawnFlags"/> to apply.</param>
910+ protected virtual void RoleAdded ( Player player , SpawnReason spawnReason , RoleSpawnFlags roleSpawnFlags )
911+ {
912+ #pragma warning disable CS0618
913+ RoleAdded ( player ) ;
914+ #pragma warning restore CS0618
915+ }
902916
903917 /// <summary>
904918 /// Called after the role has been added to the player.
905919 /// </summary>
906920 /// <param name="player">The <see cref="Player"/> the role was added to.</param>
921+ [ Obsolete ( "Use RoleAdded(Player, SpawnReason, RoleSpawnFlags) instead." ) ]
907922 protected virtual void RoleAdded ( Player player )
908923 {
909924 }
@@ -912,6 +927,20 @@ protected virtual void RoleAdded(Player player)
912927 /// Called 1 frame before the role is removed from the player.
913928 /// </summary>
914929 /// <param name="player">The <see cref="Player"/> the role was removed from.</param>
930+ /// <param name="spawnReason">The <see cref="SpawnReason"/>.</param>
931+ /// <param name="roleSpawnFlags">The <see cref="RoleSpawnFlags"/> to apply.</param>
932+ protected virtual void RoleRemoved ( Player player , SpawnReason spawnReason , RoleSpawnFlags roleSpawnFlags )
933+ {
934+ #pragma warning disable CS0618
935+ RoleRemoved ( player ) ;
936+ #pragma warning restore CS0618
937+ }
938+
939+ /// <summary>
940+ /// Called 1 frame before the role is removed from the player.
941+ /// </summary>
942+ /// <param name="player">The <see cref="Player"/> the role was removed from.</param>
943+ [ Obsolete ( "Use RoleRemoved(Player, SpawnReason, RoleSpawnFlags) instead." ) ]
915944 protected virtual void RoleRemoved ( Player player )
916945 {
917946 }
@@ -925,13 +954,13 @@ private void OnInternalChangingNickname(ChangingNicknameEventArgs ev)
925954 private void OnInternalSpawned ( SpawnedEventArgs ev )
926955 {
927956 if ( ! IgnoreSpawnSystem && SpawnChance > 0 && ! Check ( ev . Player ) && ev . Player . Role . Type == Role && Loader . Random . NextDouble ( ) * 100 <= SpawnChance )
928- AddRole ( ev . Player ) ;
957+ AddRole ( ev . Player , ev . Reason , false ) ;
929958 }
930959
931960 private void OnInternalChangingRole ( ChangingRoleEventArgs ev )
932961 {
933962 if ( ev . IsAllowed && ev . Reason != SpawnReason . Destroyed && Check ( ev . Player ) && ( ( ev . NewRole == RoleTypeId . Spectator && ! KeepRoleOnDeath ) || ( ev . NewRole != RoleTypeId . Spectator && ! KeepRoleOnChangingRole ) ) )
934- RemoveRole ( ev . Player ) ;
963+ RemoveRole ( ev . Player , ev . Reason , ev . SpawnFlags ) ;
935964 }
936965
937966 private void OnSpawningRagdoll ( SpawningRagdollEventArgs ev )
@@ -942,4 +971,4 @@ private void OnSpawningRagdoll(SpawningRagdollEventArgs ev)
942971
943972 private void OnDestroying ( DestroyingEventArgs ev ) => RemoveRole ( ev . Player ) ;
944973 }
945- }
974+ }
0 commit comments