@@ -2,13 +2,15 @@ import { ABResolverOptions } from '@sofie-automation/blueprints-integration'
22import { clone } from '@sofie-automation/corelib/dist/lib'
33import * as _ from 'underscore'
44
5+ export type PlayerId = number | string
6+
57export interface SessionRequest {
68 readonly id : string
79 readonly start : number
810 readonly end : number | undefined
911 readonly optional ?: boolean
1012 readonly lookaheadRank ?: number
11- playerId ?: number | string
13+ playerId ?: PlayerId
1214}
1315
1416export interface AssignmentResult {
@@ -21,7 +23,7 @@ export interface AssignmentResult {
2123}
2224
2325interface SlotAvailability {
24- id : number | string
26+ id : PlayerId
2527 before : ( SessionRequest & { end : number } ) | null
2628 after : SessionRequest | null
2729 clashes : SessionRequest [ ]
@@ -55,7 +57,7 @@ function safeMin<T>(arr: T[], func: (val: T) => number): T | undefined {
5557 */
5658export function resolveAbAssignmentsFromRequests (
5759 resolverOptions : ABResolverOptions ,
58- playerIds : Array < number | string > ,
60+ playerIds : PlayerId [ ] ,
5961 rawRequests : SessionRequest [ ] ,
6062 now : number // Current time
6163) : AssignmentResult {
@@ -80,7 +82,7 @@ export function resolveAbAssignmentsFromRequests(
8082 return res
8183 }
8284
83- const originalLookaheadAssignments : Record < string , number | string > = { }
85+ const originalLookaheadAssignments : Record < string , PlayerId > = { }
8486 for ( const req of rawRequests ) {
8587 if ( req . lookaheadRank !== undefined && req . playerId !== undefined ) {
8688 originalLookaheadAssignments [ req . id ] = req . playerId
@@ -104,7 +106,7 @@ export function resolveAbAssignmentsFromRequests(
104106 pendingRequests = grouped [ undefined as any ]
105107
106108 // build map of slots and what they already have assigned
107- const slots : Map < number | string , SessionRequest [ ] > = new Map ( )
109+ const slots = new Map < PlayerId , SessionRequest [ ] > ( )
108110 _ . each ( playerIds , ( id ) => slots . set ( id , grouped [ id ] || [ ] ) )
109111
110112 const beforeHasGap = ( p : SlotAvailability , req : SessionRequest ) : boolean =>
@@ -311,73 +313,67 @@ export function resolveAbAssignmentsFromRequests(
311313 }
312314 }
313315
316+ assignPlayersForLookahead ( slots , res , originalLookaheadAssignments , safeNow )
317+
318+ return res
319+ }
320+
321+ function assignPlayersForLookahead (
322+ slots : Map < PlayerId , SessionRequest [ ] > ,
323+ res : AssignmentResult ,
324+ originalLookaheadAssignments : Record < string , PlayerId > ,
325+ safeNow : number
326+ ) {
314327 // Ensure lookahead gets assigned based on priority not some randomness
315328 // Includes slots which have either no sessions, or the last has a known end time
316- const lastSessionPerSlot : Record < number | string , number | undefined > = { } // playerId, end
329+ const lastSessionPerSlot = new Map < PlayerId , number > ( ) // playerId, end
317330 for ( const [ playerId , sessions ] of slots ) {
318331 const last = _ . last ( sessions . filter ( ( s ) => s . lookaheadRank === undefined ) )
319332 if ( ! last ) {
320- lastSessionPerSlot [ playerId ] = Number . NEGATIVE_INFINITY
333+ lastSessionPerSlot . set ( playerId , Number . NEGATIVE_INFINITY )
321334 } else if ( last . end !== undefined ) {
322335 // If there is a defined end, then it can be useful after that point of time
323- lastSessionPerSlot [ playerId ] = last . end
336+ lastSessionPerSlot . set ( playerId , last . end )
324337 }
325338 }
326339
327340 // Filter down to the lookaheads that we should try to assign
328341 const lookaheadsToAssign = _ . sortBy (
329342 res . requests . filter ( ( r ) => r . lookaheadRank !== undefined ) ,
330343 ( r ) => r . lookaheadRank
331- ) . slice ( 0 , Object . keys ( lastSessionPerSlot ) . length )
332-
333- // Persist previous players if possible
334- const remainingLookaheads : SessionRequest [ ] = [ ]
335- for ( const req of lookaheadsToAssign ) {
336- delete req . playerId
337-
344+ ) . slice ( 0 , lastSessionPerSlot . size )
345+
346+ const [ playersClearNow , playersClearSoon ] = _ . partition (
347+ Array . from ( lastSessionPerSlot . entries ( ) ) ,
348+ ( session ) => session [ 1 ] < safeNow
349+ )
350+
351+ // Assign the players which are clear right now
352+ const playersClearNowIds = new Set ( playersClearNow . map ( ( p ) => p [ 0 ] ) )
353+ // First persist any previous players
354+ const lookaheadsToAssignNow = lookaheadsToAssign . slice ( 0 , playersClearNow . length )
355+ for ( const req of lookaheadsToAssignNow ) {
338356 const prevPlayer = originalLookaheadAssignments [ req . id ]
339- if ( prevPlayer === undefined ) {
340- remainingLookaheads . push ( req )
341- } else {
342- // Ensure the assignment is ok
343- const slotEnd = lastSessionPerSlot [ prevPlayer ]
344- if ( slotEnd === undefined || slotEnd >= safeNow ) {
345- // It isnt available for this lookahead, or isnt visible yet
346- remainingLookaheads . push ( req )
347- } else {
348- // It is ours, so remove the player from the pool
349- req . playerId = prevPlayer
350- delete lastSessionPerSlot [ req . playerId ]
351- }
352- }
353- }
354-
355- // Assign any remaining lookaheads
356- const sortedSlots = _ . sortBy ( Object . entries < number | undefined > ( lastSessionPerSlot ) , ( s ) => s [ 1 ] ?? 0 )
357- for ( let i = 0 ; i < remainingLookaheads . length ; i ++ ) {
358- const slot = sortedSlots [ i ]
359- const req = remainingLookaheads [ i ]
360-
361- if ( slot ) {
362- // Check if we were originally given a player index rather than a string Id
363- if ( playerIds . find ( ( id ) => typeof id === 'number' && id === Number ( slot [ 0 ] ) ) ) {
364- req . playerId = Number ( slot [ 0 ] )
365- } else {
366- req . playerId = slot [ 0 ]
367- }
357+ if ( prevPlayer !== undefined && playersClearNowIds . delete ( prevPlayer ) ) {
358+ req . playerId = prevPlayer
368359 } else {
369360 delete req . playerId
370361 }
371362 }
363+ // Then fill in the blanks
364+ const playersClearNowRemainingIds = Array . from ( playersClearNowIds )
365+ for ( const req of lookaheadsToAssignNow ) {
366+ if ( req . playerId === undefined ) req . playerId = playersClearNowRemainingIds . shift ( )
367+ }
372368
373- return res
369+ // Assign the players which are clear soon. These aren't visible, so don't need to preserve anything
370+ const lookaheadsToAssignSoon = lookaheadsToAssign . slice ( playersClearNow . length )
371+ for ( const req of lookaheadsToAssignSoon ) {
372+ req . playerId = playersClearSoon . shift ( ) ?. [ 0 ]
373+ }
374374}
375375
376- function getAvailability (
377- id : number | string ,
378- thisReq : SessionRequest ,
379- orderedRequests : SessionRequest [ ]
380- ) : SlotAvailability {
376+ function getAvailability ( id : PlayerId , thisReq : SessionRequest , orderedRequests : SessionRequest [ ] ) : SlotAvailability {
381377 const res : SlotAvailability = {
382378 id,
383379 before : null ,
0 commit comments