55using System ;
66using System . Collections . Generic ;
77using System . Linq ;
8+ using System . Reflection ;
89using UncomplicatedCustomTeams . API . Enums ;
910using UncomplicatedCustomTeams . API . Storage ;
1011using UncomplicatedCustomTeams . Utilities ;
12+ using UnityEngine ;
1113using Utils . NonAllocLINQ ;
1214
1315namespace UncomplicatedCustomTeams . API . Features
@@ -17,11 +19,12 @@ public class SummonedTeam
1719 /// <summary>
1820 /// Gets a list of every spawned <see cref="Team"/> as <see cref="SummonedTeam"/>
1921 /// </summary>
20- public static List < SummonedTeam > List { get ; } = new ( ) ;
22+ public static List < SummonedTeam > List { get ; } = [ ] ;
23+ public static event Action < SummonedTeam > OnTeamSummoned ;
2124
2225 public string Id { get ; }
2326
24- public List < SummonedCustomRole > Players { get ; } = new ( ) ;
27+ public List < SummonedCustomRole > Players { get ; } = [ ] ;
2528
2629 public Team Team { get ; }
2730
@@ -77,36 +80,14 @@ public bool IsTeamEliminated()
7780 }
7881
7982 /// <summary>
80- /// Checks if the given team is a custom team.
83+ /// Checks if a player is part of any spawned custom team.
8184 /// </summary>
82- public static bool IsCustomTeam ( PlayerRoles . Team team )
85+ public static bool IsPlayerInCustomTeam ( Player player )
8386 {
84- return Team . List . Any ( t => t . Name == team . ToString ( ) ) ;
85- }
86-
87- /// <summary>
88- /// Checks if the round should end based on the alive teams and winning conditions.
89- /// </summary>
90- public static void CheckRoundEndCondition ( )
91- {
92- var aliveTeams = Player . List . Where ( p => p . IsAlive )
93- . Select ( p => p . Role . Team )
94- . Where ( t => ! IsCustomTeam ( t ) )
95- . Distinct ( )
96- . ToList ( ) ;
87+ if ( player == null )
88+ return false ;
9789
98- var winningTeams = Team . GetWinningTeams ( ) ;
99- bool hasWinningTeamAlive = aliveTeams . Any ( team => winningTeams . Contains ( team ) ) ;
100- bool onlyWinningTeamsRemain = aliveTeams . All ( team => winningTeams . Contains ( team ) ) ;
101- bool hasAliveCustomTeam = SummonedTeam . List . Any ( team => team . HasAlivePlayers ( ) ) ;
102-
103- if ( hasWinningTeamAlive && onlyWinningTeamsRemain && hasAliveCustomTeam )
104- {
105- if ( ! Round . IsLocked )
106- {
107- Round . EndRound ( ) ;
108- }
109- }
90+ return List . Any ( summonedTeam => summonedTeam . Players . Any ( summonedRole => summonedRole . Player . Id == player . Id ) ) ;
11091 }
11192
11293 /// <summary>
@@ -186,7 +167,7 @@ public static SummonedTeam Summon(Team team, IEnumerable<Player> players)
186167 int totalAllowed = team . TeamRoles . Sum ( r => r . MaxPlayers ) ;
187168 int assigned = 0 ;
188169
189- var random = new Random ( ) ;
170+ var random = new System . Random ( ) ;
190171 var roleQueue = team . TeamRoles
191172 . Where ( r => r . Priority != RolePriority . None )
192173 . GroupBy ( r => r . Priority )
@@ -229,6 +210,9 @@ public static SummonedTeam Summon(Team team, IEnumerable<Player> players)
229210 }
230211
231212 team . SpawnCount ++ ;
213+
214+ OnTeamSummoned ? . Invoke ( SummonedTeam ) ;
215+
232216 return SummonedTeam ;
233217 }
234218
@@ -238,26 +222,109 @@ public static SummonedTeam Summon(Team team, IEnumerable<Player> players)
238222 /// </summary>
239223 private static IEnumerator < float > PlaySoundSequence ( Team team )
240224 {
241- AudioPlayer audioPlayer = AudioPlayer . CreateOrGet ( $ "Global_Audio_{ team . Id } ", onIntialCreation : ( p ) =>
225+ Assembly audioAssembly = AppDomain . CurrentDomain . GetAssemblies ( )
226+ . FirstOrDefault ( a => a . GetName ( ) . Name . Contains ( "AudioPlayer" ) ) ;
227+
228+ if ( audioAssembly == null )
229+ {
230+ LogManager . Warn ( "AudioPlayerApi assembly not found." ) ;
231+ yield break ;
232+ }
233+
234+ Type audioPlayerType = audioAssembly . GetTypes ( ) . FirstOrDefault ( t => t . Name == "AudioPlayer" && t . IsClass ) ;
235+ if ( audioPlayerType == null )
242236 {
243- p . AddSpeaker ( "Main" , isSpatial : false , maxDistance : 5000f ) ;
244- } ) ;
245- float volume = Clamp ( team . SoundVolume , 1f , 100f ) ;
237+ yield break ;
238+ }
239+
240+ var createOrGetMethod = audioPlayerType . GetMethod ( "CreateOrGet" , BindingFlags . Public | BindingFlags . Static ) ;
241+ var addSpeakerMethod = audioPlayerType . GetMethods ( BindingFlags . Public | BindingFlags . Instance )
242+ . FirstOrDefault ( m => m . Name == "AddSpeaker" && m . GetParameters ( ) . Length == 5 ) ;
243+ var addClipMethod = audioPlayerType . GetMethod ( "AddClip" , BindingFlags . Public | BindingFlags . Instance ) ;
244+
245+ if ( createOrGetMethod == null || addSpeakerMethod == null || addClipMethod == null )
246+ {
247+ yield break ;
248+ }
249+
250+ string startClipId = null ;
251+ int startIndex = - 1 ;
252+ float startDelay = 0f ;
246253
247254 for ( int i = 0 ; i < team . SoundPaths . Count ; i ++ )
248255 {
249- var sound = team . SoundPaths [ i ] ;
256+ var s = team . SoundPaths [ i ] ;
257+ if ( ! string . IsNullOrEmpty ( s . Path ) && s . Path != "/path/to/your/ogg/file" )
258+ {
259+ startClipId = $ "sound_{ team . Id } _{ i } ";
260+ startIndex = i ;
261+ startDelay = s . Delay ;
262+ break ;
263+ }
264+ }
250265
251- if ( string . IsNullOrEmpty ( sound . Path ) || sound . Path == "/path/to/your/ogg/file" )
252- continue ;
266+ if ( startDelay > 0f )
267+ {
268+ yield return Timing . WaitForSeconds ( startDelay ) ;
269+ }
270+
271+ object audioPlayerInstance = null ;
272+ try
273+ {
274+ LogManager . Debug ( $ "Creating AudioPlayer with AutoPlay Clip: { startClipId ?? "NULL" } ") ;
275+
276+ object [ ] parameters =
277+ [
278+ $ "Global_Audio_{ team . Id } ",
279+ startClipId ,
280+ null ,
281+ true ,
282+ true ,
283+ null ,
284+ ( byte ) 0 ,
285+ null ,
286+ null
287+ ] ;
288+
289+ audioPlayerInstance = createOrGetMethod . Invoke ( null , parameters ) ;
290+ }
291+ catch ( Exception ex )
292+ {
293+ LogManager . Error ( $ "Failed to create Audio Player: { ex } ") ;
294+ yield break ;
295+ }
253296
254- if ( sound . Delay > 0f )
297+ float volume = team . SoundVolume ;
298+ if ( volume > 1.5f ) volume /= 100f ;
299+ volume = Mathf . Clamp ( volume , 0.1f , 1.5f ) ;
300+
301+ if ( audioPlayerInstance != null )
302+ {
303+ try
255304 {
256- yield return Timing . WaitForSeconds ( sound . Delay ) ;
305+ addSpeakerMethod . Invoke ( audioPlayerInstance , [ "Main" , 1.0f , false , 0f , 5000f ] ) ;
257306 }
307+ catch ( Exception ) { }
308+
309+ for ( int i = 0 ; i < team . SoundPaths . Count ; i ++ )
310+ {
311+ if ( i == startIndex ) continue ;
312+
313+ var sound = team . SoundPaths [ i ] ;
314+ if ( string . IsNullOrEmpty ( sound . Path ) || sound . Path . Contains ( "/path/to/" ) ) continue ;
315+
316+ if ( sound . Delay > 0f ) yield return Timing . WaitForSeconds ( sound . Delay ) ;
258317
259- string clipId = $ "sound_{ team . Id } _{ i } ";
260- audioPlayer . AddClip ( clipId , volume ) ;
318+ try
319+ {
320+ string clipId = $ "sound_{ team . Id } _{ i } ";
321+ addClipMethod . Invoke ( audioPlayerInstance , [ clipId , volume , false , true ] ) ;
322+ }
323+ catch ( Exception ex )
324+ {
325+ LogManager . Error ( $ "Error queuing next clip: { ex . Message } ") ;
326+ }
327+ }
261328 }
262329 }
263330
0 commit comments