@3dsource/angular-unreal-module 0.0.177 → 0.0.182
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -4,10 +4,10 @@ import { NgTemplateOutlet, NgOptimizedImage, JsonPipe } from '@angular/common';
|
|
|
4
4
|
import { createAction, props, createReducer, on, createFeature, createSelector, Store, provideState } from '@ngrx/store';
|
|
5
5
|
import { Actions, ofType, createEffect, provideEffects } from '@ngrx/effects';
|
|
6
6
|
import { Subject, skip, share, timer, of, take, defer, switchMap, from, throwError, Observable, EMPTY, retry, merge, timeout as timeout$1, repeat, BehaviorSubject, interval, map as map$1, takeUntil as takeUntil$1, fromEvent, tap as tap$1, throttleTime, delay, concat, debounceTime, mergeMap, NEVER, ignoreElements, startWith, scan, timestamp, pairwise, concatMap, animationFrameScheduler, shareReplay, firstValueFrom, asyncScheduler, filter as filter$1, withLatestFrom as withLatestFrom$1, Subscription, bufferTime, combineLatestWith } from 'rxjs';
|
|
7
|
-
import { whereNot, lerp, clampf, Falsy, generateUuid, Truthy, Logger, tapLog, Semaphore, COLOR_CODES, getCanvasCached, getSnapshot, fitIntoRectangle, where, KeyboardNumericCode, InvertedKeyMap, HEXtoRGB, RGBtoHSV, inverseLerp, HSVtoRGB, RGBtoHEX, fpIsASameAsB } from '@3dsource/utils';
|
|
8
7
|
import { UNREAL_CONFIG } from '@3dsource/angular-unreal-module/config';
|
|
9
8
|
export { UNREAL_CONFIG } from '@3dsource/angular-unreal-module/config';
|
|
10
|
-
import { filter, takeUntil, catchError,
|
|
9
|
+
import { tap, filter, takeUntil, catchError, map, timeout, finalize, first, switchMap as switchMap$1, distinctUntilChanged, withLatestFrom, exhaustMap, takeWhile, debounceTime as debounceTime$1, take as take$1, startWith as startWith$1 } from 'rxjs/operators';
|
|
10
|
+
import { v4 } from 'uuid';
|
|
11
11
|
import { DialogRef, DIALOG_DATA, Dialog } from '@angular/cdk/dialog';
|
|
12
12
|
import { HttpClient } from '@angular/common/http';
|
|
13
13
|
import { ScrollStrategyOptions } from '@angular/cdk/overlay';
|
|
@@ -36,10 +36,10 @@ class UnrealButtonComponent {
|
|
|
36
36
|
event.preventDefault();
|
|
37
37
|
this.clicked.emit(event);
|
|
38
38
|
}
|
|
39
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
40
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.
|
|
39
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
40
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.3", type: UnrealButtonComponent, isStandalone: true, selector: "app-unreal-button", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, weight: { classPropertyName: "weight", publicName: "weight", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, isDisabled: { classPropertyName: "isDisabled", publicName: "isDisabled", isSignal: true, isRequired: false, transformFunction: null }, testID: { classPropertyName: "testID", publicName: "data-testid", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<button\n (click)=\"handleClick($event)\"\n [attr.data-testid]=\"testID() || null\"\n [attr.aria-label]=\"ariaLabel()\"\n [class.unreal-button--primary]=\"weight() === 'primary'\"\n [class.unreal-button--lg]=\"size() === 'lg'\"\n [class.unreal-button--full-width]=\"fullWidth()\"\n [disabled]=\"isDisabled()\"\n [type]=\"type()\"\n class=\"unreal-button\"\n>\n <span><ng-content></ng-content></span>\n</button>\n", styles: [".unreal-button{--unrealButtonHeight: 36px;--unrealButtonPaddings: 0 12px;--unrealButtonBorderRadius: 6px;--unrealButtonFontSize: var(--src-font-size-sm, 14px);--unrealButtonLineHeight: var(--src-font-line-sm, 20px);--unrealButtonWidth: auto;--unrealButtonBgColor: transparent;--unrealButtonBorderColor: var(--src-border-button-basic, #e5e7eb);--unrealButtonBorder: 1px solid var(--unrealButtonBorderColor);--unrealButtonFontColor: var(--src-text-ui-secondary-main, #111827);--unrealButtonFontWeight: var(--src-font-weight-medium, 500);--unrealButtonFocusRingSize: 4px;--unrealButtonFocusRingColor: var( --src-shadow-light, rgba(148, 163, 184, .16) );--unrealButtonBoxShadow: 0 -1px 0 0 var(--src-shadow-hard, rgba(71, 85, 105, .24)) inset, 0 1px 0 0 var(--src-shadow-light, rgba(148, 163, 184, .16));position:relative;display:flex;justify-content:center;align-items:center;width:var(--unrealButtonWidth);height:var(--unrealButtonHeight);padding:var(--unrealButtonPaddings);font-weight:var(--unrealButtonFontWeight);font-size:var(--unrealButtonFontSize);font-style:normal;line-height:var(--unrealButtonLineHeight);text-align:center;color:var(--unrealButtonFontColor);letter-spacing:0;white-space:nowrap;border:none;background-color:var(--unrealButtonBgColor);border-radius:var(--unrealButtonBorderRadius);box-shadow:var(--unrealButtonBoxShadow);cursor:pointer}.unreal-button:after{content:\"\";position:absolute;inset:0;border-radius:var(--unrealButtonBorderRadius);border:var(--unrealButtonBorder)}.unreal-button>span{display:flex;justify-content:center;align-items:center;gap:var(--src-gap-md, 6px);width:auto;font-size:inherit;line-height:inherit;color:inherit;font-weight:inherit}.unreal-button:disabled{--unrealButtonBgColor: var( --src-ui-accent-disabled, rgba(148, 163, 184, .24) );--unrealButtonFontColor: var(--src-text-ui-secondary-disabled, #9ca3af);--unrealButtonBoxShadow: none;--unrealButtonBorder: none;--unrealButtonBorderColor: transparent;cursor:default;pointer-events:none}.unreal-button:focus-visible{--unrealButtonBorderColor: var(--src-border-button-basic-hover, #9ca3af);outline:none;box-shadow:0 0 0 var(--unrealButtonFocusRingSize) var(--unrealButtonFocusRingColor)}@media(pointer:fine){.unreal-button:hover{--unrealButtonBgColor: var( --src-ui-secondary-default-hover, rgba(148, 163, 184, .08) );--unrealButtonBorderColor: var(--src-border-button-basic-hover, #9ca3af)}}.unreal-button--primary{--unrealButtonBgColor: var(--unreal-accent, var(--src-ui-accent-default, #017bff));--unrealButtonBorder: none;--unrealButtonFontColor: var(--unreal-accent-text, var(--src-text-ui-primary-main, #fff));--unrealButtonFocusRingColor: var( --src-shadow-accent-light, rgba(1, 123, 255, .16) )}@media(pointer:fine){.unreal-button--primary:hover{--unrealButtonBgColor: var(--unreal-accent-hover, var(--src-ui-accent-default-hover, #016fe6));--unrealButtonFontColor: var(--unreal-accent-text, var(--src-text-ui-primary-main, #fff))}}.unreal-button--lg{--unrealButtonHeight: 44px;--unrealButtonPaddings: 0 16px;--unrealButtonBorderRadius: 8px;--unrealButtonFontSize: var(--src-font-size-base, 16px);--unrealButtonLineHeight: var(--src-font-line-base, 24px);--unrealButtonFocusRingSize: 6px;--unrealButtonBoxShadow: 0 -1px 0 0 var(--src-shadow-hard, rgba(71, 85, 105, .24)) inset, 0 2px 0 0 var(--src-shadow-light, rgba(148, 163, 184, .16))}.unreal-button--lg>span{gap:var(--src-gap-md, 8px)}.unreal-button--full-width{--unrealButtonWidth: 100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
41
41
|
}
|
|
42
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
42
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealButtonComponent, decorators: [{
|
|
43
43
|
type: Component,
|
|
44
44
|
args: [{ selector: 'app-unreal-button', changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\n (click)=\"handleClick($event)\"\n [attr.data-testid]=\"testID() || null\"\n [attr.aria-label]=\"ariaLabel()\"\n [class.unreal-button--primary]=\"weight() === 'primary'\"\n [class.unreal-button--lg]=\"size() === 'lg'\"\n [class.unreal-button--full-width]=\"fullWidth()\"\n [disabled]=\"isDisabled()\"\n [type]=\"type()\"\n class=\"unreal-button\"\n>\n <span><ng-content></ng-content></span>\n</button>\n", styles: [".unreal-button{--unrealButtonHeight: 36px;--unrealButtonPaddings: 0 12px;--unrealButtonBorderRadius: 6px;--unrealButtonFontSize: var(--src-font-size-sm, 14px);--unrealButtonLineHeight: var(--src-font-line-sm, 20px);--unrealButtonWidth: auto;--unrealButtonBgColor: transparent;--unrealButtonBorderColor: var(--src-border-button-basic, #e5e7eb);--unrealButtonBorder: 1px solid var(--unrealButtonBorderColor);--unrealButtonFontColor: var(--src-text-ui-secondary-main, #111827);--unrealButtonFontWeight: var(--src-font-weight-medium, 500);--unrealButtonFocusRingSize: 4px;--unrealButtonFocusRingColor: var( --src-shadow-light, rgba(148, 163, 184, .16) );--unrealButtonBoxShadow: 0 -1px 0 0 var(--src-shadow-hard, rgba(71, 85, 105, .24)) inset, 0 1px 0 0 var(--src-shadow-light, rgba(148, 163, 184, .16));position:relative;display:flex;justify-content:center;align-items:center;width:var(--unrealButtonWidth);height:var(--unrealButtonHeight);padding:var(--unrealButtonPaddings);font-weight:var(--unrealButtonFontWeight);font-size:var(--unrealButtonFontSize);font-style:normal;line-height:var(--unrealButtonLineHeight);text-align:center;color:var(--unrealButtonFontColor);letter-spacing:0;white-space:nowrap;border:none;background-color:var(--unrealButtonBgColor);border-radius:var(--unrealButtonBorderRadius);box-shadow:var(--unrealButtonBoxShadow);cursor:pointer}.unreal-button:after{content:\"\";position:absolute;inset:0;border-radius:var(--unrealButtonBorderRadius);border:var(--unrealButtonBorder)}.unreal-button>span{display:flex;justify-content:center;align-items:center;gap:var(--src-gap-md, 6px);width:auto;font-size:inherit;line-height:inherit;color:inherit;font-weight:inherit}.unreal-button:disabled{--unrealButtonBgColor: var( --src-ui-accent-disabled, rgba(148, 163, 184, .24) );--unrealButtonFontColor: var(--src-text-ui-secondary-disabled, #9ca3af);--unrealButtonBoxShadow: none;--unrealButtonBorder: none;--unrealButtonBorderColor: transparent;cursor:default;pointer-events:none}.unreal-button:focus-visible{--unrealButtonBorderColor: var(--src-border-button-basic-hover, #9ca3af);outline:none;box-shadow:0 0 0 var(--unrealButtonFocusRingSize) var(--unrealButtonFocusRingColor)}@media(pointer:fine){.unreal-button:hover{--unrealButtonBgColor: var( --src-ui-secondary-default-hover, rgba(148, 163, 184, .08) );--unrealButtonBorderColor: var(--src-border-button-basic-hover, #9ca3af)}}.unreal-button--primary{--unrealButtonBgColor: var(--unreal-accent, var(--src-ui-accent-default, #017bff));--unrealButtonBorder: none;--unrealButtonFontColor: var(--unreal-accent-text, var(--src-text-ui-primary-main, #fff));--unrealButtonFocusRingColor: var( --src-shadow-accent-light, rgba(1, 123, 255, .16) )}@media(pointer:fine){.unreal-button--primary:hover{--unrealButtonBgColor: var(--unreal-accent-hover, var(--src-ui-accent-default-hover, #016fe6));--unrealButtonFontColor: var(--unreal-accent-text, var(--src-text-ui-primary-main, #fff))}}.unreal-button--lg{--unrealButtonHeight: 44px;--unrealButtonPaddings: 0 16px;--unrealButtonBorderRadius: 8px;--unrealButtonFontSize: var(--src-font-size-base, 16px);--unrealButtonLineHeight: var(--src-font-line-base, 24px);--unrealButtonFocusRingSize: 6px;--unrealButtonBoxShadow: 0 -1px 0 0 var(--src-shadow-hard, rgba(71, 85, 105, .24)) inset, 0 2px 0 0 var(--src-shadow-light, rgba(148, 163, 184, .16))}.unreal-button--lg>span{gap:var(--src-gap-md, 8px)}.unreal-button--full-width{--unrealButtonWidth: 100%}\n"] }]
|
|
45
45
|
}], propDecorators: { type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], weight: [{ type: i0.Input, args: [{ isSignal: true, alias: "weight", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], isDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDisabled", required: false }] }], testID: [{ type: i0.Input, args: [{ isSignal: true, alias: "data-testid", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], clicked: [{ type: i0.Output, args: ["clicked"] }] } });
|
|
@@ -307,6 +307,179 @@ const MouseButtonsMask = {
|
|
|
307
307
|
FifthButton: 16, // Browser Forward button.
|
|
308
308
|
};
|
|
309
309
|
|
|
310
|
+
/**
|
|
311
|
+
* `KeyboardEvent.code` → the Windows virtual-key code Unreal expects.
|
|
312
|
+
*
|
|
313
|
+
* Only keys whose `event.keyCode` cannot be trusted belong here. The browser
|
|
314
|
+
* already resolves `keyCode` correctly for everything else, so the table exists
|
|
315
|
+
* for two cases: browsers that disagree on a value (Gecko reports the
|
|
316
|
+
* punctuation keys by ASCII — `;` as 59, `=` as 61, `-` as 173) and keys Unreal
|
|
317
|
+
* numbers differently from the DOM (the right-hand modifiers, the Cmd/Win keys).
|
|
318
|
+
*
|
|
319
|
+
* The numpad digits, `NumpadDecimal` and `NumpadEnter` are the exception to the
|
|
320
|
+
* rule above, and the reason it is worded as a rule. A numpad key reports the
|
|
321
|
+
* same `code` in both NumLock states but a different virtual key — `Numpad4` is
|
|
322
|
+
* 37/`VK_LEFT` with NumLock off and 100/`VK_NUMPAD4` with it on. Their entries
|
|
323
|
+
* here hold the NumLock-*off* values, so an entry wins over the value the
|
|
324
|
+
* browser resolved and pins that state: with NumLock on the engine is told
|
|
325
|
+
* `VK_LEFT`. Read `event.keyCode` directly if you need the other state.
|
|
326
|
+
* `NumpadAdd`/`Subtract`/`Multiply`/`Divide` carry no such caveat — they do not
|
|
327
|
+
* change with NumLock.
|
|
328
|
+
*
|
|
329
|
+
* `SpecialKeyCodes` in `./buttons-codes` repeats seven of these entries with
|
|
330
|
+
* the same values. The two are kept apart because both are public API; merging
|
|
331
|
+
* them would be a breaking change.
|
|
332
|
+
*
|
|
333
|
+
* `InvertedKeyMap` is consequently lossy. `NumpadEnter` and `Numpad4/8/6/2`
|
|
334
|
+
* share their values with `Enter` and `Arrow*`, and the derivation keeps the
|
|
335
|
+
* last name written for a value, so those five cannot be reached through it —
|
|
336
|
+
* which is what makes them unnameable through the numeric form of
|
|
337
|
+
* `useKeyboardKeys()`. The `OSLeft`/`MetaLeft` and `OSRight`/`MetaRight` pairs
|
|
338
|
+
* share a value on purpose: they are legacy and current names for the same
|
|
339
|
+
* physical key.
|
|
340
|
+
*/
|
|
341
|
+
const KeyboardNumericCode = {
|
|
342
|
+
Backspace: 8,
|
|
343
|
+
Tab: 9,
|
|
344
|
+
// The NumLock-*off* virtual keys. Declared before `Enter` and the arrows on
|
|
345
|
+
// purpose: those come later and so win the `InvertedKeyMap` derivation, which
|
|
346
|
+
// keeps 13 resolving to `Enter` and 37-40 to `Arrow*`.
|
|
347
|
+
Numpad5: 12,
|
|
348
|
+
NumpadEnter: 13,
|
|
349
|
+
Numpad9: 33,
|
|
350
|
+
Numpad3: 34,
|
|
351
|
+
Numpad1: 35,
|
|
352
|
+
Numpad7: 36,
|
|
353
|
+
Numpad4: 37,
|
|
354
|
+
Numpad8: 38,
|
|
355
|
+
Numpad6: 39,
|
|
356
|
+
Numpad2: 40,
|
|
357
|
+
Numpad0: 45,
|
|
358
|
+
NumpadDecimal: 46,
|
|
359
|
+
Enter: 13,
|
|
360
|
+
ShiftLeft: 16,
|
|
361
|
+
ControlLeft: 17,
|
|
362
|
+
AltLeft: 18,
|
|
363
|
+
Escape: 27,
|
|
364
|
+
Space: 32,
|
|
365
|
+
ArrowLeft: 37,
|
|
366
|
+
ArrowUp: 38,
|
|
367
|
+
ArrowRight: 39,
|
|
368
|
+
ArrowDown: 40,
|
|
369
|
+
Digit0: 48,
|
|
370
|
+
Digit1: 49,
|
|
371
|
+
Digit2: 50,
|
|
372
|
+
Digit3: 51,
|
|
373
|
+
Digit4: 52,
|
|
374
|
+
Digit5: 53,
|
|
375
|
+
Digit6: 54,
|
|
376
|
+
Digit7: 55,
|
|
377
|
+
Digit8: 56,
|
|
378
|
+
Digit9: 57,
|
|
379
|
+
KeyA: 65,
|
|
380
|
+
KeyB: 66,
|
|
381
|
+
KeyC: 67,
|
|
382
|
+
KeyD: 68,
|
|
383
|
+
KeyE: 69,
|
|
384
|
+
KeyF: 70,
|
|
385
|
+
KeyG: 71,
|
|
386
|
+
KeyH: 72,
|
|
387
|
+
KeyI: 73,
|
|
388
|
+
KeyJ: 74,
|
|
389
|
+
KeyK: 75,
|
|
390
|
+
KeyL: 76,
|
|
391
|
+
KeyM: 77,
|
|
392
|
+
KeyN: 78,
|
|
393
|
+
KeyO: 79,
|
|
394
|
+
KeyP: 80,
|
|
395
|
+
KeyQ: 81,
|
|
396
|
+
KeyR: 82,
|
|
397
|
+
KeyS: 83,
|
|
398
|
+
KeyT: 84,
|
|
399
|
+
KeyU: 85,
|
|
400
|
+
KeyV: 86,
|
|
401
|
+
KeyW: 87,
|
|
402
|
+
KeyX: 88,
|
|
403
|
+
KeyY: 89,
|
|
404
|
+
KeyZ: 90,
|
|
405
|
+
// Chrome/Safari report 91 for the left Cmd/Win key, Firefox on macOS 224.
|
|
406
|
+
// The right one shares keyCode 93 with ContextMenu on Chrome/Safari, making
|
|
407
|
+
// the two indistinguishable. Unreal numbers them 91 and 92.
|
|
408
|
+
OSLeft: 91,
|
|
409
|
+
MetaLeft: 91,
|
|
410
|
+
OSRight: 92,
|
|
411
|
+
MetaRight: 92,
|
|
412
|
+
ContextMenu: 93,
|
|
413
|
+
NumpadMultiply: 106,
|
|
414
|
+
NumpadAdd: 107,
|
|
415
|
+
NumpadSubtract: 109,
|
|
416
|
+
NumpadDivide: 111,
|
|
417
|
+
F1: 112,
|
|
418
|
+
F2: 113,
|
|
419
|
+
F3: 114,
|
|
420
|
+
F4: 115,
|
|
421
|
+
F5: 116,
|
|
422
|
+
F6: 117,
|
|
423
|
+
F7: 118,
|
|
424
|
+
F8: 119,
|
|
425
|
+
F9: 120,
|
|
426
|
+
F10: 121,
|
|
427
|
+
F11: 122,
|
|
428
|
+
F12: 123,
|
|
429
|
+
NumLock: 144,
|
|
430
|
+
ScrollLock: 145,
|
|
431
|
+
Semicolon: 186,
|
|
432
|
+
Equal: 187,
|
|
433
|
+
Comma: 188,
|
|
434
|
+
Minus: 189,
|
|
435
|
+
Period: 190,
|
|
436
|
+
Slash: 191,
|
|
437
|
+
Backquote: 192,
|
|
438
|
+
BracketLeft: 219,
|
|
439
|
+
Backslash: 220,
|
|
440
|
+
BracketRight: 221,
|
|
441
|
+
Quote: 222,
|
|
442
|
+
IntlBackslash: 226,
|
|
443
|
+
// Unreal keeps distinct codes for the right-hand modifiers; the DOM reports
|
|
444
|
+
// both sides of each pair under the same `keyCode`.
|
|
445
|
+
ShiftRight: 253,
|
|
446
|
+
ControlRight: 254,
|
|
447
|
+
AltRight: 255,
|
|
448
|
+
};
|
|
449
|
+
/**
|
|
450
|
+
* The `keyCode` a browser reports while an IME is composing (`VK_PROCESSKEY`).
|
|
451
|
+
*
|
|
452
|
+
* `event.code` keeps naming the *physical* key during composition — `KeyW`,
|
|
453
|
+
* `KeyA` and friends — so a consumer that forwards keys has to drop these
|
|
454
|
+
* events explicitly or typing CJK text turns into keystrokes.
|
|
455
|
+
*/
|
|
456
|
+
const IME_PROCESS_KEY = 229;
|
|
457
|
+
/**
|
|
458
|
+
* Codes of the keys that are themselves modifiers. A modifier's own `keydown`
|
|
459
|
+
* already reports `ctrlKey`/`metaKey` as pressed, so a "browser shortcut in
|
|
460
|
+
* flight" check has to exempt them or `ControlRight` would block itself.
|
|
461
|
+
*/
|
|
462
|
+
const MODIFIER_KEY_CODES = new Set([
|
|
463
|
+
'ShiftLeft',
|
|
464
|
+
'ShiftRight',
|
|
465
|
+
'ControlLeft',
|
|
466
|
+
'ControlRight',
|
|
467
|
+
'AltLeft',
|
|
468
|
+
'AltRight',
|
|
469
|
+
'MetaLeft',
|
|
470
|
+
'MetaRight',
|
|
471
|
+
'OSLeft',
|
|
472
|
+
'OSRight',
|
|
473
|
+
]);
|
|
474
|
+
const InvertedKeyMapValues = {};
|
|
475
|
+
//For use for InvertedKeyMap[32] will return 'Space' and so on
|
|
476
|
+
const InvertedKeyMap = InvertedKeyMapValues;
|
|
477
|
+
Object.entries(KeyboardNumericCode).forEach(
|
|
478
|
+
// @ts-expect-error @typescript-eslint/ban-ts-comment
|
|
479
|
+
([key, value]) => {
|
|
480
|
+
InvertedKeyMapValues[value] = key;
|
|
481
|
+
});
|
|
482
|
+
|
|
310
483
|
const ControlScheme = {
|
|
311
484
|
// A mouse can lock inside the WebRTC player, so the user can simply move the
|
|
312
485
|
// mouse to control the orientation of the camera. The user presses the
|
|
@@ -491,8 +664,12 @@ const UnrealStatusMessage = {
|
|
|
491
664
|
};
|
|
492
665
|
|
|
493
666
|
const COMMAND_EXILE_TIMEOUT_MS = 10_000;
|
|
667
|
+
const normalizeId = (value) => String(value).trim().replace(/ +/gi, '_').toLowerCase();
|
|
494
668
|
function exileExpiredCommands(commandsInProgress, idToRemove, now) {
|
|
495
|
-
|
|
669
|
+
// Case-insensitive, like the `whereNot()` predicate this replaces: a caller
|
|
670
|
+
// supplies `correlationId`, and it round-trips through the engine.
|
|
671
|
+
const idKey = normalizeId(idToRemove);
|
|
672
|
+
let remaining = commandsInProgress.filter(({ id }) => normalizeId(id) !== idKey);
|
|
496
673
|
const expired = remaining.filter(({ timeStamp }) => now - timeStamp > COMMAND_EXILE_TIMEOUT_MS);
|
|
497
674
|
if (expired.length) {
|
|
498
675
|
const expiredIds = new Set(expired.map(({ id }) => id));
|
|
@@ -825,6 +1002,488 @@ const unrealFeature = createFeature({
|
|
|
825
1002
|
reducer: unrealReducer,
|
|
826
1003
|
});
|
|
827
1004
|
|
|
1005
|
+
function fitIntoRectangle(objectRect, areaRect, round = true, fixedRatio = null) {
|
|
1006
|
+
const result = { x: 0, y: 0, w: 0, h: 0, scale: 1 };
|
|
1007
|
+
const ratio = objectRect.h / objectRect.w;
|
|
1008
|
+
if (objectRect.h > objectRect.w) {
|
|
1009
|
+
result.h = areaRect.h;
|
|
1010
|
+
result.w = areaRect.h / ratio;
|
|
1011
|
+
if (result.w > areaRect.w) {
|
|
1012
|
+
result.w = areaRect.w;
|
|
1013
|
+
result.h = areaRect.w * ratio;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
else {
|
|
1017
|
+
result.w = areaRect.w;
|
|
1018
|
+
result.h = areaRect.w * ratio;
|
|
1019
|
+
if (result.h > areaRect.h) {
|
|
1020
|
+
result.h = areaRect.h;
|
|
1021
|
+
result.w = areaRect.h / ratio;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
if (fixedRatio) {
|
|
1025
|
+
result.w = objectRect.w * fixedRatio;
|
|
1026
|
+
result.h = objectRect.h * fixedRatio;
|
|
1027
|
+
}
|
|
1028
|
+
const wOut = round ? Math.floor(result.w) : result.w;
|
|
1029
|
+
const hOut = round ? Math.floor(result.h) : result.h;
|
|
1030
|
+
return {
|
|
1031
|
+
x: areaRect.x + (areaRect.w - wOut) / 2,
|
|
1032
|
+
y: areaRect.y + (areaRect.h - hOut) / 2,
|
|
1033
|
+
w: wOut,
|
|
1034
|
+
h: hOut,
|
|
1035
|
+
scale: wOut / objectRect.w,
|
|
1036
|
+
};
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
const canvasCacheObj = {};
|
|
1040
|
+
function getCanvasCached(id) {
|
|
1041
|
+
if (!canvasCacheObj[id]) {
|
|
1042
|
+
const canvas = document.createElement('canvas');
|
|
1043
|
+
const ctx = canvas.getContext('2d');
|
|
1044
|
+
if (!ctx) {
|
|
1045
|
+
throw new Error('Canvas 2D context is unavailable.');
|
|
1046
|
+
}
|
|
1047
|
+
canvasCacheObj[id] = {
|
|
1048
|
+
canvas,
|
|
1049
|
+
ctx,
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
return canvasCacheObj[id];
|
|
1053
|
+
}
|
|
1054
|
+
function sourceDimensions(imageElement) {
|
|
1055
|
+
const naturalWidth = 'naturalWidth' in imageElement ? imageElement.naturalWidth : 0;
|
|
1056
|
+
const naturalHeight = 'naturalHeight' in imageElement ? imageElement.naturalHeight : 0;
|
|
1057
|
+
return {
|
|
1058
|
+
width: naturalWidth || imageElement.width,
|
|
1059
|
+
height: naturalHeight || imageElement.height,
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
function canvasContext(canvas) {
|
|
1063
|
+
const context = canvas.getContext('2d');
|
|
1064
|
+
if (!context) {
|
|
1065
|
+
throw new Error('Canvas 2D context is unavailable.');
|
|
1066
|
+
}
|
|
1067
|
+
return context;
|
|
1068
|
+
}
|
|
1069
|
+
function getSnapshot2(imageElement, maxWidth = 1024, output = 'image/png', quality = 0.9) {
|
|
1070
|
+
const canvasHelper = document.createElement('canvas');
|
|
1071
|
+
const drawCTX = canvasContext(canvasHelper);
|
|
1072
|
+
const dimensions = sourceDimensions(imageElement);
|
|
1073
|
+
const prop = fitIntoRectangle({
|
|
1074
|
+
x: 0,
|
|
1075
|
+
y: 0,
|
|
1076
|
+
w: dimensions.width,
|
|
1077
|
+
h: dimensions.height,
|
|
1078
|
+
}, {
|
|
1079
|
+
x: 0,
|
|
1080
|
+
y: 0,
|
|
1081
|
+
w: maxWidth,
|
|
1082
|
+
h: dimensions.height,
|
|
1083
|
+
});
|
|
1084
|
+
const width = prop.w;
|
|
1085
|
+
const height = prop.h;
|
|
1086
|
+
canvasHelper.width = width;
|
|
1087
|
+
canvasHelper.height = height;
|
|
1088
|
+
drawCTX.save();
|
|
1089
|
+
drawCTX.clearRect(0, 0, width, height);
|
|
1090
|
+
drawCTX.drawImage(imageElement, 0, 0, width, height);
|
|
1091
|
+
drawCTX.restore();
|
|
1092
|
+
if (output === 'canvas') {
|
|
1093
|
+
return canvasHelper;
|
|
1094
|
+
}
|
|
1095
|
+
return canvasHelper.toDataURL(output, quality);
|
|
1096
|
+
}
|
|
1097
|
+
function getSnapshot(imageElement, maxWidth = 1024, output = 'image/png', quality = 0.9) {
|
|
1098
|
+
const canvasHelper = document.createElement('canvas');
|
|
1099
|
+
const drawCTX = canvasContext(canvasHelper);
|
|
1100
|
+
const dimensions = sourceDimensions(imageElement);
|
|
1101
|
+
const prop = fitIntoRectangle({
|
|
1102
|
+
x: 0,
|
|
1103
|
+
y: 0,
|
|
1104
|
+
w: dimensions.width,
|
|
1105
|
+
h: dimensions.height,
|
|
1106
|
+
}, {
|
|
1107
|
+
x: 0,
|
|
1108
|
+
y: 0,
|
|
1109
|
+
w: dimensions.width / 2,
|
|
1110
|
+
h: dimensions.height,
|
|
1111
|
+
});
|
|
1112
|
+
const width = prop.w;
|
|
1113
|
+
const height = prop.h;
|
|
1114
|
+
canvasHelper.width = width;
|
|
1115
|
+
canvasHelper.height = height;
|
|
1116
|
+
drawCTX.save();
|
|
1117
|
+
drawCTX.clearRect(0, 0, width, height);
|
|
1118
|
+
drawCTX.drawImage(imageElement, 0, 0, width, height);
|
|
1119
|
+
drawCTX.restore();
|
|
1120
|
+
if (width > maxWidth * 2) {
|
|
1121
|
+
return getSnapshot(canvasHelper, maxWidth, output, quality);
|
|
1122
|
+
}
|
|
1123
|
+
return getSnapshot2(imageElement, maxWidth, output, quality);
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
/* eslint-disable prefer-const */
|
|
1127
|
+
/**
|
|
1128
|
+
* Colour-space conversions used by the dev stat graph overlay.
|
|
1129
|
+
*
|
|
1130
|
+
* Carried over verbatim; `HSVtoRGB` reassigns its locals, hence the
|
|
1131
|
+
* file-level `prefer-const` exemption.
|
|
1132
|
+
*/
|
|
1133
|
+
function HEXtoRGB(color) {
|
|
1134
|
+
if (typeof color === 'string') {
|
|
1135
|
+
color = parseInt(color.replace('#', ''), 16);
|
|
1136
|
+
}
|
|
1137
|
+
const r = (color >> 16) & 255;
|
|
1138
|
+
const g = (color >> 8) & 255;
|
|
1139
|
+
const b = color & 255;
|
|
1140
|
+
return { r: r, g: g, b: b };
|
|
1141
|
+
}
|
|
1142
|
+
function RGBtoHEX(r, g, b) {
|
|
1143
|
+
let redColor = r.toString(16);
|
|
1144
|
+
let greenColor = g.toString(16);
|
|
1145
|
+
let blackColor = b.toString(16);
|
|
1146
|
+
if (redColor.length === 1) {
|
|
1147
|
+
redColor = '0' + redColor;
|
|
1148
|
+
}
|
|
1149
|
+
if (greenColor.length === 1) {
|
|
1150
|
+
greenColor = '0' + greenColor;
|
|
1151
|
+
}
|
|
1152
|
+
if (blackColor.length === 1) {
|
|
1153
|
+
blackColor = '0' + blackColor;
|
|
1154
|
+
}
|
|
1155
|
+
return (redColor + greenColor + blackColor).toUpperCase();
|
|
1156
|
+
}
|
|
1157
|
+
/**
|
|
1158
|
+
* RGB from the respective figures, HSV sequences in terms of returns.
|
|
1159
|
+
* RGB values are as follows.
|
|
1160
|
+
* R - a number from 0 to 255
|
|
1161
|
+
* G - a number from 0 to 255
|
|
1162
|
+
* B - a number from 0 to 255
|
|
1163
|
+
*
|
|
1164
|
+
* HSV values are as follows.
|
|
1165
|
+
* H - a number between 360-0
|
|
1166
|
+
* S - number between 0 and 1.0
|
|
1167
|
+
* V - number between 0 and 1.0
|
|
1168
|
+
*
|
|
1169
|
+
* Cannot compute, including alpha.
|
|
1170
|
+
* @ Param r the red (R) indicating the number (0x00 to 0xFF to)
|
|
1171
|
+
* @ Param g green (G) indicates the number (0x00 to 0xFF to)
|
|
1172
|
+
* @ Param b blue (B) shows the number (0x00 to 0xFF to)
|
|
1173
|
+
* @ Return HSV values as [H, S, V]
|
|
1174
|
+
**/
|
|
1175
|
+
function RGBtoHSV(r, g, b) {
|
|
1176
|
+
r /= 255;
|
|
1177
|
+
g /= 255;
|
|
1178
|
+
b /= 255;
|
|
1179
|
+
let h = 0;
|
|
1180
|
+
let s;
|
|
1181
|
+
let x, y;
|
|
1182
|
+
if (r >= g)
|
|
1183
|
+
x = r;
|
|
1184
|
+
else
|
|
1185
|
+
x = g;
|
|
1186
|
+
if (b > x)
|
|
1187
|
+
x = b;
|
|
1188
|
+
if (r <= g)
|
|
1189
|
+
y = r;
|
|
1190
|
+
else
|
|
1191
|
+
y = g;
|
|
1192
|
+
if (b < y)
|
|
1193
|
+
y = b;
|
|
1194
|
+
const v = x;
|
|
1195
|
+
const c = x - y;
|
|
1196
|
+
if (x === 0)
|
|
1197
|
+
s = 0;
|
|
1198
|
+
else
|
|
1199
|
+
s = c / x;
|
|
1200
|
+
if (s !== 0) {
|
|
1201
|
+
if (r === x) {
|
|
1202
|
+
h = (g - b) / c;
|
|
1203
|
+
}
|
|
1204
|
+
else {
|
|
1205
|
+
if (g === x) {
|
|
1206
|
+
h = 2 + (b - r) / c;
|
|
1207
|
+
}
|
|
1208
|
+
else {
|
|
1209
|
+
if (b === x) {
|
|
1210
|
+
h = 4 + (r - g) / c;
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
h = h * 60;
|
|
1215
|
+
if (h < 0)
|
|
1216
|
+
h = h + 360;
|
|
1217
|
+
}
|
|
1218
|
+
return [h, s, v];
|
|
1219
|
+
}
|
|
1220
|
+
/**
|
|
1221
|
+
* HSV from each of the RGB values to determine a return as a number[].
|
|
1222
|
+
* RGB values are as follows.
|
|
1223
|
+
* R - a number from 0 to 255
|
|
1224
|
+
* G - a number from 0 to 255
|
|
1225
|
+
* B - a number from 0 to 255
|
|
1226
|
+
*
|
|
1227
|
+
* HSV values are as follows.
|
|
1228
|
+
* H - a number between 360-0
|
|
1229
|
+
* S - number between 0 and 1.0
|
|
1230
|
+
* V - number between 0 and 1.0
|
|
1231
|
+
*
|
|
1232
|
+
* H is replaced with equivalent numbers in the range of the 360-0 that is out of range.
|
|
1233
|
+
* Cannot compute, including alpha.
|
|
1234
|
+
*
|
|
1235
|
+
* @ Param h hue (Hue) number that indicates (to 360-0)
|
|
1236
|
+
* @ Param s the saturation (Saturation) shows the number (0.0 to 1.0)
|
|
1237
|
+
* @ Param v lightness (Value) indicates the number (0.0 to 1.0)
|
|
1238
|
+
* @ Return RGB values into a number[] of [R, G, B]
|
|
1239
|
+
**/
|
|
1240
|
+
function HSVtoRGB(h, s, v) {
|
|
1241
|
+
let r = 0, g = 0, b = 0;
|
|
1242
|
+
let i, x, y, z;
|
|
1243
|
+
if (s < 0) {
|
|
1244
|
+
s = 0;
|
|
1245
|
+
}
|
|
1246
|
+
if (s > 1) {
|
|
1247
|
+
s = 1;
|
|
1248
|
+
}
|
|
1249
|
+
if (v < 0) {
|
|
1250
|
+
v = 0;
|
|
1251
|
+
}
|
|
1252
|
+
if (v > 1) {
|
|
1253
|
+
v = 1;
|
|
1254
|
+
}
|
|
1255
|
+
h = h % 360;
|
|
1256
|
+
if (h < 0) {
|
|
1257
|
+
h += 360;
|
|
1258
|
+
}
|
|
1259
|
+
h /= 60;
|
|
1260
|
+
i = h >> 0;
|
|
1261
|
+
x = v * (1 - s);
|
|
1262
|
+
y = v * (1 - s * (h - i));
|
|
1263
|
+
z = v * (1 - s * (1 - h + i));
|
|
1264
|
+
switch (i) {
|
|
1265
|
+
case 0:
|
|
1266
|
+
r = v;
|
|
1267
|
+
g = z;
|
|
1268
|
+
b = x;
|
|
1269
|
+
break;
|
|
1270
|
+
case 1:
|
|
1271
|
+
r = y;
|
|
1272
|
+
g = v;
|
|
1273
|
+
b = x;
|
|
1274
|
+
break;
|
|
1275
|
+
case 2:
|
|
1276
|
+
r = x;
|
|
1277
|
+
g = v;
|
|
1278
|
+
b = z;
|
|
1279
|
+
break;
|
|
1280
|
+
case 3:
|
|
1281
|
+
r = x;
|
|
1282
|
+
g = y;
|
|
1283
|
+
b = v;
|
|
1284
|
+
break;
|
|
1285
|
+
case 4:
|
|
1286
|
+
r = z;
|
|
1287
|
+
g = x;
|
|
1288
|
+
b = v;
|
|
1289
|
+
break;
|
|
1290
|
+
case 5:
|
|
1291
|
+
r = v;
|
|
1292
|
+
g = x;
|
|
1293
|
+
b = y;
|
|
1294
|
+
break;
|
|
1295
|
+
}
|
|
1296
|
+
return [(r * 255) >> 0, (g * 255) >> 0, (b * 255) >> 0];
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
/** Console palette for the Unreal/Cirrus message log. */
|
|
1300
|
+
const COLOR_CODES = {
|
|
1301
|
+
TO_UNREAL: ['#ffffff', '#005912', `UNREAL <-`],
|
|
1302
|
+
TAP_LOG: ['#ffff00', '#1976d2', ' [TAPLOG]'],
|
|
1303
|
+
FROM_UNREAL: ['#ffff00', '#898989', 'UNREAL ->'],
|
|
1304
|
+
FROM_UNREAL_ERROR: ['#ffffff', '#ff0000', 'UNREAL ERROR ->'],
|
|
1305
|
+
FROM_CIRRUS: ['#ffffff', '#ef702b', 'CIRRUS ->'],
|
|
1306
|
+
FROM_CIRRUS_ERROR: ['#ffffff', '#ff0000', 'CIRRUS ->'],
|
|
1307
|
+
TO_CIRRUS: ['#ffffff', '#3c9738', 'CIRRUS <-'],
|
|
1308
|
+
};
|
|
1309
|
+
|
|
1310
|
+
function generateUuid() {
|
|
1311
|
+
return v4();
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
/**
|
|
1315
|
+
* Truthiness with the string forms folded in: `'false'`, `'undefined'` and
|
|
1316
|
+
* `'null'` are falsy here, which `Boolean` would call true.
|
|
1317
|
+
*/
|
|
1318
|
+
const Truthy = (value) => !!value && value !== 'false' && value !== 'undefined' && value !== 'null';
|
|
1319
|
+
/** The inverse of {@link Truthy}. */
|
|
1320
|
+
const Falsy = (value) => !Truthy(value);
|
|
1321
|
+
|
|
1322
|
+
/* eslint-disable no-console -- this file *is* the console wrapper; every call
|
|
1323
|
+
is gated behind `Logger.isDevMode`. */
|
|
1324
|
+
/**
|
|
1325
|
+
* Left-pads `input` to `size`, then trims to the last `size` characters — a
|
|
1326
|
+
* value longer than `size` is truncated, not left as-is.
|
|
1327
|
+
*/
|
|
1328
|
+
function pad(input, size, symbol = '0') {
|
|
1329
|
+
let s = input + '';
|
|
1330
|
+
while (s.length < size) {
|
|
1331
|
+
s = symbol + s;
|
|
1332
|
+
}
|
|
1333
|
+
return s.slice(-size);
|
|
1334
|
+
}
|
|
1335
|
+
/** `UTC:HH:MM:SS.mmm` for the current instant. */
|
|
1336
|
+
function timeUTCToString() {
|
|
1337
|
+
const date = new Date();
|
|
1338
|
+
return `UTC:${pad(date.getUTCHours(), 2)}:${pad(date.getUTCMinutes(), 2)}:${pad(date.getUTCSeconds(), 2)}.${pad(date.getUTCMilliseconds(), 3)}`;
|
|
1339
|
+
}
|
|
1340
|
+
class Logger {
|
|
1341
|
+
// Guard the top-level `localStorage` access so the package stays importable
|
|
1342
|
+
// in non-browser contexts (Node CLI / SSR); off the browser dev mode is off.
|
|
1343
|
+
static { this.isDevMode = typeof localStorage !== 'undefined' &&
|
|
1344
|
+
Truthy(localStorage.getItem('devMode')); }
|
|
1345
|
+
static colored(color, background, ...args) {
|
|
1346
|
+
if (!Logger.isDevMode) {
|
|
1347
|
+
return;
|
|
1348
|
+
}
|
|
1349
|
+
const [first, ...rest] = args;
|
|
1350
|
+
console.log.apply(console, [
|
|
1351
|
+
`%c ${timeUTCToString()} ${first} `,
|
|
1352
|
+
`color: ${color}; background: ${background};`,
|
|
1353
|
+
...rest,
|
|
1354
|
+
]);
|
|
1355
|
+
}
|
|
1356
|
+
static log(...args) {
|
|
1357
|
+
if (!Logger.isDevMode) {
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
console.log.apply(console, [
|
|
1361
|
+
`%c ${timeUTCToString()} [ LOG ] `,
|
|
1362
|
+
'color: black; background: #80ff80;',
|
|
1363
|
+
...args,
|
|
1364
|
+
]);
|
|
1365
|
+
}
|
|
1366
|
+
static warn(...args) {
|
|
1367
|
+
if (!Logger.isDevMode) {
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
console.warn.apply(console, [
|
|
1371
|
+
`%c ${timeUTCToString()} WARN `,
|
|
1372
|
+
'color: black; background: #ffd500;',
|
|
1373
|
+
...args,
|
|
1374
|
+
]);
|
|
1375
|
+
}
|
|
1376
|
+
static info(...args) {
|
|
1377
|
+
if (!Logger.isDevMode) {
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
console.log.apply(console, [
|
|
1381
|
+
`%c ${timeUTCToString()} [ INFO ] `,
|
|
1382
|
+
'color: white; background: blue;',
|
|
1383
|
+
...args,
|
|
1384
|
+
]);
|
|
1385
|
+
}
|
|
1386
|
+
static error(...args) {
|
|
1387
|
+
if (!Logger.isDevMode) {
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
console.error.apply(console, [
|
|
1391
|
+
`%c ${timeUTCToString()} ERROR `,
|
|
1392
|
+
'color: white; background: red;',
|
|
1393
|
+
...args,
|
|
1394
|
+
]);
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
/** Clamps `value` between `min` and `max`; an inverted range yields `min`. */
|
|
1399
|
+
function clampf(min, max, value) {
|
|
1400
|
+
if (min > max) {
|
|
1401
|
+
return min;
|
|
1402
|
+
}
|
|
1403
|
+
return Math.min(max, Math.max(min, value));
|
|
1404
|
+
}
|
|
1405
|
+
/** Linear interpolation; `value` is clamped to the 0..1 range first. */
|
|
1406
|
+
function lerp(min, max, value) {
|
|
1407
|
+
value = clampf(0, 1, value);
|
|
1408
|
+
return value * (max - min) + min;
|
|
1409
|
+
}
|
|
1410
|
+
/**
|
|
1411
|
+
* The inverse of {@link lerp}: where `value` sits between `min` and `max`.
|
|
1412
|
+
*
|
|
1413
|
+
* Returns 1 when the range is empty, to avoid dividing by zero.
|
|
1414
|
+
*/
|
|
1415
|
+
function inverseLerp(min, max, value, clampToNormal = false) {
|
|
1416
|
+
if (clampToNormal) {
|
|
1417
|
+
value = Math.min(max, value);
|
|
1418
|
+
value = Math.max(min, value);
|
|
1419
|
+
}
|
|
1420
|
+
const difference = max - min;
|
|
1421
|
+
if (difference === 0) {
|
|
1422
|
+
return 1;
|
|
1423
|
+
}
|
|
1424
|
+
const result = (value - min) / difference;
|
|
1425
|
+
if (clampToNormal) {
|
|
1426
|
+
return Math.min(1, Math.max(0, result));
|
|
1427
|
+
}
|
|
1428
|
+
return result;
|
|
1429
|
+
}
|
|
1430
|
+
const EPSILON = 0.01;
|
|
1431
|
+
/**
|
|
1432
|
+
* Floating-point equality within `Epsilon` (default `0.01`).
|
|
1433
|
+
*
|
|
1434
|
+
* Note the `||` fallback: passing `0` uses the default, it does not compare
|
|
1435
|
+
* exactly.
|
|
1436
|
+
*/
|
|
1437
|
+
function fpIsASameAsB(A, B, Epsilon) {
|
|
1438
|
+
Epsilon = Epsilon || EPSILON;
|
|
1439
|
+
return Math.abs(A - B) < Epsilon;
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
/**
|
|
1443
|
+
* A counting semaphore: `acquire()` resolves once a slot is free, `release()`
|
|
1444
|
+
* hands the slot to the longest-waiting caller.
|
|
1445
|
+
*/
|
|
1446
|
+
class Semaphore {
|
|
1447
|
+
constructor(maxConcurrency) {
|
|
1448
|
+
this.maxConcurrency = maxConcurrency;
|
|
1449
|
+
this.tasks = [];
|
|
1450
|
+
this.currentCount = 0;
|
|
1451
|
+
}
|
|
1452
|
+
acquire() {
|
|
1453
|
+
return new Promise((resolve) => {
|
|
1454
|
+
if (this.currentCount < this.maxConcurrency) {
|
|
1455
|
+
this.currentCount++;
|
|
1456
|
+
resolve();
|
|
1457
|
+
}
|
|
1458
|
+
else {
|
|
1459
|
+
this.tasks.push(resolve);
|
|
1460
|
+
}
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1463
|
+
release() {
|
|
1464
|
+
if (this.tasks.length > 0) {
|
|
1465
|
+
const nextTask = this.tasks.shift();
|
|
1466
|
+
if (nextTask) {
|
|
1467
|
+
nextTask();
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
else if (this.currentCount > 0) {
|
|
1471
|
+
this.currentCount--;
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
const tapLog = (text, ...args) => (source) => source.pipe(tap((data) => {
|
|
1477
|
+
Logger.colored(...COLOR_CODES.TAP_LOG, text, data, ...args);
|
|
1478
|
+
}));
|
|
1479
|
+
|
|
1480
|
+
// Internal only. Deliberately absent from src/public-api.ts — these are the
|
|
1481
|
+
// symbols this package used to pull from @3dsource/utils. Exporting them would
|
|
1482
|
+
// re-create the coupling this folder exists to remove.
|
|
1483
|
+
//
|
|
1484
|
+
// Import this barrel from production code ('../utils' / '../../utils'), never
|
|
1485
|
+
// the individual files: the specs mock the barrel as a unit.
|
|
1486
|
+
|
|
828
1487
|
/**
|
|
829
1488
|
* `'metabox'` — the default when `UNREAL_CONFIG` omits `mode` — speaks the full
|
|
830
1489
|
* Metabox command protocol. `'default'` targets a stock Pixel Streaming
|
|
@@ -953,10 +1612,10 @@ class WebrtcErrorModalComponent {
|
|
|
953
1612
|
close() {
|
|
954
1613
|
this.#dialogRef.close();
|
|
955
1614
|
}
|
|
956
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
957
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.
|
|
1615
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: WebrtcErrorModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1616
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.3", type: WebrtcErrorModalComponent, isStandalone: true, selector: "app-webrtc-error-modal", ngImport: i0, template: "<div [attr.data-testid]=\"'webrtc-error-modal'\" class=\"unreal-modal\">\n <header class=\"unreal-modal__header\"></header>\n <section class=\"unreal-modal__body\">\n <div [attr.data-testid]=\"'title'\" class=\"unreal-modal__title\">\n WebRTC error\n </div>\n <div style=\"text-align: left\">\n An internet connection type (WebRTC) appears to be blocked either by your\n browser settings or your current network. If WebRTC is blocked on your\n browser you may be able to adjust these settings yourself based on\n instructions here:\n <a href=\"https://myownconference.com/blog/en/webrtc/\" target=\"blank\"\n >https://myownconference.com/blog/en/webrtc/</a\n >\n <br /><br />\n Trying a different web browser may help confirm this as well. If WebRTC is\n blocked by your network, try switching to a different network if possible\n or contact your network administrator.<br /><br />\n WebRTC is common, safe and increasingly utilised method for streaming real\n time 3D experiences via a web browser. It typically consumes no more\n bandwidth than streaming an HD video.\n </div>\n </section>\n <footer class=\"unreal-modal__footer\">\n <app-unreal-button\n (clicked)=\"closeModalWithCirrusDisconnect()\"\n [data-testid]=\"'close-webrtc-error-modal'\"\n weight=\"primary\"\n >\n Ok\n </app-unreal-button>\n </footer>\n</div>\n", styles: [".unreal-modal{--unrealModalWidth: 422px;--unrealModalMaxWidth: calc(100% - 16px) ;--unrealModalMaxHeight: 80vh;--unrealModalBg: var(--src-surface-container-main, #fff);--unrealModalBoxShadow: 0 16px 36px 4px var(--src-shadow-hard, rgba(71, 85, 105, .24)), 0 1px 4px 0 var(--src-shadow-light, rgba(148, 163, 184, .16));--unrealModalBorderRadius: var(--src-layout-radius-const-rounded-md, 12px);--unrealModalTitleSize: var(--src-font-size-base, 16px);--unrealModalTitleLineHeight: var(--src-font-line-base, 24px);--unrealModalTitleColor: var(--src-text-body-main, #111827);--unrealModalBodyPadding: var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-2xl, 32px) var(--src-layout-padding-const-xl, 24px);--unrealModalTitleBorder: none;--unrealModalFooterBorder: 1px solid var(--src-border-container-light, rgba(148, 163, 184, .16));display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto;width:var(--unrealModalWidth);max-width:var(--unrealModalMaxWidth);max-height:var(--unrealModalMaxHeight);margin:auto;background-color:var(--unrealModalBg);border-radius:var(--unrealModalBorderRadius);box-shadow:var(--unrealModalBoxShadow);color:var(--src-text-body-secondary, #4b5563);font-family:var(--src-font-family-header, Inter);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:var(--src-font-line-sm, 20px)}.unreal-modal .unreal-modal__header{position:relative;display:flex;padding:0;width:100%;border-bottom:var(--unrealModalTitleBorder)}.unreal-modal .unreal-modal__body{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);gap:var(--src-layout-gap-const-md, 12px);padding:var(--unrealModalBodyPadding);overflow:auto;scrollbar-width:thin;scrollbar-color:var(--src-border-container-basic, rgba(148, 163, 184, .24)) transparent}.unreal-modal .unreal-modal__body .unreal-modal__title{grid-column:1/-1}.unreal-modal .unreal-modal__body::-webkit-scrollbar{width:4px}.unreal-modal .unreal-modal__body::-webkit-scrollbar-track{background:transparent}.unreal-modal .unreal-modal__body::-webkit-scrollbar-thumb{background-color:var(--src-border-container-basic, rgba(148, 163, 184, .24));border-radius:10px}.unreal-modal .unreal-modal__footer{display:flex;justify-content:flex-end;align-items:center;padding:var(--src-layout-padding-const-md, 12px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px);width:100%;border-top:var(--unrealModalFooterBorder);gap:var(--src-layout-gap-const-sm, 8px)}.unreal-modal .unreal-modal__title{font-size:var(--unrealModalTitleSize);font-weight:600;line-height:var(--unrealModalTitleLineHeight);color:var(--unrealModalTitleColor);word-break:break-word}.unreal-modal .unreal-modal__body{width:100%}.unreal-modal .unreal-modal__body p{color:var(--src-text-body-main, #1f2937);font-size:14px;font-style:normal;font-weight:400;line-height:24px;margin-top:0}.unreal-modal .unreal-modal__body a{word-wrap:break-word;white-space:normal}\n"], dependencies: [{ kind: "component", type: UnrealButtonComponent, selector: "app-unreal-button", inputs: ["type", "weight", "size", "fullWidth", "isDisabled", "data-testid", "ariaLabel"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
958
1617
|
}
|
|
959
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
1618
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: WebrtcErrorModalComponent, decorators: [{
|
|
960
1619
|
type: Component,
|
|
961
1620
|
args: [{ selector: 'app-webrtc-error-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent], template: "<div [attr.data-testid]=\"'webrtc-error-modal'\" class=\"unreal-modal\">\n <header class=\"unreal-modal__header\"></header>\n <section class=\"unreal-modal__body\">\n <div [attr.data-testid]=\"'title'\" class=\"unreal-modal__title\">\n WebRTC error\n </div>\n <div style=\"text-align: left\">\n An internet connection type (WebRTC) appears to be blocked either by your\n browser settings or your current network. If WebRTC is blocked on your\n browser you may be able to adjust these settings yourself based on\n instructions here:\n <a href=\"https://myownconference.com/blog/en/webrtc/\" target=\"blank\"\n >https://myownconference.com/blog/en/webrtc/</a\n >\n <br /><br />\n Trying a different web browser may help confirm this as well. If WebRTC is\n blocked by your network, try switching to a different network if possible\n or contact your network administrator.<br /><br />\n WebRTC is common, safe and increasingly utilised method for streaming real\n time 3D experiences via a web browser. It typically consumes no more\n bandwidth than streaming an HD video.\n </div>\n </section>\n <footer class=\"unreal-modal__footer\">\n <app-unreal-button\n (clicked)=\"closeModalWithCirrusDisconnect()\"\n [data-testid]=\"'close-webrtc-error-modal'\"\n weight=\"primary\"\n >\n Ok\n </app-unreal-button>\n </footer>\n</div>\n", styles: [".unreal-modal{--unrealModalWidth: 422px;--unrealModalMaxWidth: calc(100% - 16px) ;--unrealModalMaxHeight: 80vh;--unrealModalBg: var(--src-surface-container-main, #fff);--unrealModalBoxShadow: 0 16px 36px 4px var(--src-shadow-hard, rgba(71, 85, 105, .24)), 0 1px 4px 0 var(--src-shadow-light, rgba(148, 163, 184, .16));--unrealModalBorderRadius: var(--src-layout-radius-const-rounded-md, 12px);--unrealModalTitleSize: var(--src-font-size-base, 16px);--unrealModalTitleLineHeight: var(--src-font-line-base, 24px);--unrealModalTitleColor: var(--src-text-body-main, #111827);--unrealModalBodyPadding: var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-2xl, 32px) var(--src-layout-padding-const-xl, 24px);--unrealModalTitleBorder: none;--unrealModalFooterBorder: 1px solid var(--src-border-container-light, rgba(148, 163, 184, .16));display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto;width:var(--unrealModalWidth);max-width:var(--unrealModalMaxWidth);max-height:var(--unrealModalMaxHeight);margin:auto;background-color:var(--unrealModalBg);border-radius:var(--unrealModalBorderRadius);box-shadow:var(--unrealModalBoxShadow);color:var(--src-text-body-secondary, #4b5563);font-family:var(--src-font-family-header, Inter);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:var(--src-font-line-sm, 20px)}.unreal-modal .unreal-modal__header{position:relative;display:flex;padding:0;width:100%;border-bottom:var(--unrealModalTitleBorder)}.unreal-modal .unreal-modal__body{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);gap:var(--src-layout-gap-const-md, 12px);padding:var(--unrealModalBodyPadding);overflow:auto;scrollbar-width:thin;scrollbar-color:var(--src-border-container-basic, rgba(148, 163, 184, .24)) transparent}.unreal-modal .unreal-modal__body .unreal-modal__title{grid-column:1/-1}.unreal-modal .unreal-modal__body::-webkit-scrollbar{width:4px}.unreal-modal .unreal-modal__body::-webkit-scrollbar-track{background:transparent}.unreal-modal .unreal-modal__body::-webkit-scrollbar-thumb{background-color:var(--src-border-container-basic, rgba(148, 163, 184, .24));border-radius:10px}.unreal-modal .unreal-modal__footer{display:flex;justify-content:flex-end;align-items:center;padding:var(--src-layout-padding-const-md, 12px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px);width:100%;border-top:var(--unrealModalFooterBorder);gap:var(--src-layout-gap-const-sm, 8px)}.unreal-modal .unreal-modal__title{font-size:var(--unrealModalTitleSize);font-weight:600;line-height:var(--unrealModalTitleLineHeight);color:var(--unrealModalTitleColor);word-break:break-word}.unreal-modal .unreal-modal__body{width:100%}.unreal-modal .unreal-modal__body p{color:var(--src-text-body-main, #1f2937);font-size:14px;font-style:normal;font-weight:400;line-height:24px;margin-top:0}.unreal-modal .unreal-modal__body a{word-wrap:break-word;white-space:normal}\n"] }]
|
|
962
1621
|
}] });
|
|
@@ -1179,10 +1838,10 @@ class CommandTelemetryService extends SubService {
|
|
|
1179
1838
|
this.trackTime(out);
|
|
1180
1839
|
funcToDecorate(out);
|
|
1181
1840
|
}
|
|
1182
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
1183
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
1841
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: CommandTelemetryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1842
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: CommandTelemetryService, providedIn: 'root' }); }
|
|
1184
1843
|
}
|
|
1185
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
1844
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: CommandTelemetryService, decorators: [{
|
|
1186
1845
|
type: Injectable,
|
|
1187
1846
|
args: [{ providedIn: 'root' }]
|
|
1188
1847
|
}], ctorParameters: () => [] });
|
|
@@ -1203,10 +1862,10 @@ class DevModeService {
|
|
|
1203
1862
|
localStorage.removeItem('devMode');
|
|
1204
1863
|
}
|
|
1205
1864
|
}
|
|
1206
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
1207
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
1865
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: DevModeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1866
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: DevModeService, providedIn: 'root' }); }
|
|
1208
1867
|
}
|
|
1209
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
1868
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: DevModeService, decorators: [{
|
|
1210
1869
|
type: Injectable,
|
|
1211
1870
|
args: [{
|
|
1212
1871
|
providedIn: 'root',
|
|
@@ -1525,10 +2184,10 @@ class RegionsPingService {
|
|
|
1525
2184
|
}
|
|
1526
2185
|
}
|
|
1527
2186
|
}
|
|
1528
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
1529
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
2187
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: RegionsPingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2188
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: RegionsPingService, providedIn: 'root' }); }
|
|
1530
2189
|
}
|
|
1531
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
2190
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: RegionsPingService, decorators: [{
|
|
1532
2191
|
type: Injectable,
|
|
1533
2192
|
args: [{ providedIn: 'root' }]
|
|
1534
2193
|
}], ctorParameters: () => [] });
|
|
@@ -1571,101 +2230,25 @@ function withStreamRequestId(wsUrl, streamRequestId) {
|
|
|
1571
2230
|
}
|
|
1572
2231
|
|
|
1573
2232
|
/**
|
|
1574
|
-
*
|
|
1575
|
-
*
|
|
1576
|
-
*
|
|
1577
|
-
* once the connection is established, then completes. This design allows
|
|
1578
|
-
* downstream operators (e.g. `tap` in `connectToCirrus`) to attach their own
|
|
1579
|
-
* event handlers before any messages arrive.
|
|
1580
|
-
*
|
|
1581
|
-
* ## Ownership model
|
|
1582
|
-
*
|
|
1583
|
-
* The factory **transfers ownership** of the WebSocket to the consumer upon
|
|
1584
|
-
* emission. Once `observer.next(ws)` fires, the consumer is responsible for
|
|
1585
|
-
* the socket's lifecycle (attaching handlers, closing when done). The teardown
|
|
1586
|
-
* logic will **never** close a socket that has been successfully delivered.
|
|
1587
|
-
*
|
|
1588
|
-
* ## Timeout
|
|
1589
|
-
*
|
|
1590
|
-
* The observable is piped through `timeout({ first: WS_TIMEOUT })`. If the
|
|
1591
|
-
* WebSocket `open` event does not fire within `WS_TIMEOUT` milliseconds, the
|
|
1592
|
-
* stream errors with a timeout message and the teardown disposes the socket.
|
|
1593
|
-
*
|
|
1594
|
-
* ## Teardown & leak prevention
|
|
1595
|
-
*
|
|
1596
|
-
* When the observable is unsubscribed (timeout, manual unsubscribe, or error),
|
|
1597
|
-
* the teardown function runs and handles two cases:
|
|
1598
|
-
*
|
|
1599
|
-
* 1. **Socket was emitted (`emitted === true`):** The consumer owns the socket.
|
|
1600
|
-
* Teardown only removes the internal event listeners — it does NOT close
|
|
1601
|
-
* the socket. Closing it here would break downstream consumers like
|
|
1602
|
-
* `connectToCirrus` that rely on the connection staying alive.
|
|
1603
|
-
*
|
|
1604
|
-
* 2. **Socket was NOT emitted (`emitted === false`):** The socket is orphaned
|
|
1605
|
-
* (nobody has a reference to it). Teardown must close it to prevent a leak.
|
|
1606
|
-
* However, calling `ws.close()` on a `CONNECTING` socket does not reliably
|
|
1607
|
-
* abort the underlying HTTP upgrade request in all browsers — the TCP
|
|
1608
|
-
* handshake may still complete asynchronously. To handle this edge case,
|
|
1609
|
-
* teardown replaces the `open` listener with a one-shot handler that calls
|
|
1610
|
-
* `ws.close()` if the connection succeeds after teardown has already run.
|
|
1611
|
-
* This ensures the orphaned socket is closed regardless of timing:
|
|
1612
|
-
*
|
|
1613
|
-
* - If `close()` aborts the connection immediately — done.
|
|
1614
|
-
* - If the browser lets the handshake complete anyway — the `open` handler
|
|
1615
|
-
* fires and closes the now-connected socket, so it doesn't linger in
|
|
1616
|
-
* the browser's network tab as a "Pending" request.
|
|
1617
|
-
*
|
|
1618
|
-
* ## Why `defer`?
|
|
1619
|
-
*
|
|
1620
|
-
* The outer `defer()` ensures a **new WebSocket** is created on each
|
|
1621
|
-
* subscription. Without it, retry operators would reuse the same (possibly
|
|
1622
|
-
* closed) socket instance. With `defer`, each retry gets a fresh connection.
|
|
1623
|
-
*
|
|
1624
|
-
* ## SSR guard
|
|
1625
|
-
*
|
|
1626
|
-
* If `window` or `WebSocket` is not available (server-side rendering),
|
|
1627
|
-
* the function returns an error observable immediately without attempting
|
|
1628
|
-
* a connection.
|
|
1629
|
-
*
|
|
1630
|
-
* ## Lifecycle flags
|
|
1631
|
-
*
|
|
1632
|
-
* - `opened` — set to `true` when the `open` event fires. Guards the `close`
|
|
1633
|
-
* handler so it only errors the observable if the socket was closed *before*
|
|
1634
|
-
* the connection was established (e.g. server rejected the upgrade).
|
|
1635
|
-
*
|
|
1636
|
-
* - `emitted` — set to `true` right before `observer.next(ws)`. Tells the
|
|
1637
|
-
* teardown function whether the socket was delivered to the consumer.
|
|
1638
|
-
* This is the flag that controls whether teardown closes the socket or
|
|
1639
|
-
* leaves it for the consumer.
|
|
2233
|
+
* Creates a WebSocket and wraps it in a single-value Observable: emits the open
|
|
2234
|
+
* socket, then completes, so a downstream `tap` can attach handlers before any
|
|
2235
|
+
* message arrives.
|
|
1640
2236
|
*
|
|
1641
|
-
*
|
|
2237
|
+
* Ownership transfers to the consumer on emission — teardown never closes a
|
|
2238
|
+
* socket it already delivered, because `connectToCirrus` needs that connection
|
|
2239
|
+
* to stay alive.
|
|
1642
2240
|
*
|
|
1643
|
-
*
|
|
1644
|
-
*
|
|
1645
|
-
*
|
|
1646
|
-
*
|
|
1647
|
-
* at two levels:
|
|
2241
|
+
* An *undelivered* socket is orphaned and teardown must close it. `ws.close()`
|
|
2242
|
+
* on a `CONNECTING` socket does not reliably abort the HTTP upgrade in every
|
|
2243
|
+
* browser, so teardown also swaps in a one-shot `open` handler that closes the
|
|
2244
|
+
* socket if the handshake completes anyway.
|
|
1648
2245
|
*
|
|
1649
|
-
*
|
|
1650
|
-
*
|
|
1651
|
-
* 2. **Outside `retry`** (e.g. in `connectToSignaling`) — kills the entire
|
|
1652
|
-
* retry loop so no further re-subscriptions occur.
|
|
2246
|
+
* The outer `defer` gives every subscription a fresh socket, so `retry` does not
|
|
2247
|
+
* reuse a closed one.
|
|
1653
2248
|
*
|
|
1654
|
-
*
|
|
1655
|
-
*
|
|
1656
|
-
*
|
|
1657
|
-
* // In connectToCirrus — takeUntil cancels the current attempt:
|
|
1658
|
-
* createWebSocket(wsUrl).pipe(
|
|
1659
|
-
* takeUntil(abort$),
|
|
1660
|
-
* tap(ws => addWsHandlers(ws)),
|
|
1661
|
-
* );
|
|
1662
|
-
*
|
|
1663
|
-
* // In connectToSignaling — takeUntil outside retry kills the loop:
|
|
1664
|
-
* defer(() => innerChain$).pipe(
|
|
1665
|
-
* retry({ delay: ... }),
|
|
1666
|
-
* takeUntil(abort$),
|
|
1667
|
-
* );
|
|
1668
|
-
* ```
|
|
2249
|
+
* There is no abort signal: cancellation is the caller's `takeUntil`, and it has
|
|
2250
|
+
* to sit at two levels — inside the per-attempt chain to cancel the in-flight
|
|
2251
|
+
* socket, and outside `retry` to stop the loop re-subscribing.
|
|
1669
2252
|
*
|
|
1670
2253
|
* @param wsUrl - The `ws://` or `wss://` URL to connect to.
|
|
1671
2254
|
* @returns Observable that emits a single open WebSocket, then completes.
|
|
@@ -1673,17 +2256,18 @@ function withStreamRequestId(wsUrl, streamRequestId) {
|
|
|
1673
2256
|
* does not support WebSocket.
|
|
1674
2257
|
*/
|
|
1675
2258
|
function createWebSocket(wsUrl, timeoutMs = WS_TIMEOUT) {
|
|
1676
|
-
//
|
|
2259
|
+
// SSR guard.
|
|
1677
2260
|
if (typeof window === 'undefined' || !('WebSocket' in window)) {
|
|
1678
2261
|
return throwError(() => new Error("Your browser doesn't support WebSocket"));
|
|
1679
2262
|
}
|
|
1680
2263
|
Logger.info('Creating socket', wsUrl);
|
|
1681
2264
|
return defer(() => new Observable((observer) => {
|
|
1682
2265
|
const ws = new WebSocket(wsUrl);
|
|
1683
|
-
//
|
|
2266
|
+
// `opened` guards `onClose` so it only errors on a close *before* the
|
|
2267
|
+
// connection was established; `emitted` tells teardown whether the
|
|
2268
|
+
// consumer already owns the socket.
|
|
1684
2269
|
let opened = false;
|
|
1685
2270
|
let emitted = false;
|
|
1686
|
-
// --- Event handlers (attached during connection, removed in teardown) ---
|
|
1687
2271
|
const onOpen = () => {
|
|
1688
2272
|
opened = true;
|
|
1689
2273
|
emitted = true;
|
|
@@ -1704,23 +2288,20 @@ function createWebSocket(wsUrl, timeoutMs = WS_TIMEOUT) {
|
|
|
1704
2288
|
ws.addEventListener('open', onOpen);
|
|
1705
2289
|
ws.addEventListener('error', onError);
|
|
1706
2290
|
ws.addEventListener('close', onClose);
|
|
1707
|
-
//
|
|
2291
|
+
// Teardown: unsubscribe, timeout, error, or complete.
|
|
1708
2292
|
return () => {
|
|
1709
2293
|
ws.removeEventListener('error', onError);
|
|
1710
2294
|
ws.removeEventListener('close', onClose);
|
|
1711
2295
|
if (!emitted &&
|
|
1712
2296
|
(ws.readyState === WebSocket.CONNECTING ||
|
|
1713
2297
|
ws.readyState === WebSocket.OPEN)) {
|
|
1714
|
-
//
|
|
1715
|
-
//
|
|
1716
|
-
// browser completes the handshake after this teardown, the
|
|
1717
|
-
// handler will close the orphaned socket immediately.
|
|
2298
|
+
// Orphaned: close it, and cover the case where the browser
|
|
2299
|
+
// completes the handshake after this teardown anyway.
|
|
1718
2300
|
ws.removeEventListener('open', onOpen);
|
|
1719
2301
|
ws.addEventListener('open', () => ws.close());
|
|
1720
|
-
// Some
|
|
1721
|
-
//
|
|
1722
|
-
//
|
|
1723
|
-
// the temporary handlers once the socket closes.
|
|
2302
|
+
// Some implementations (including `ws`) emit `error` when a
|
|
2303
|
+
// CONNECTING socket is closed. The observable is already torn
|
|
2304
|
+
// down, so swallow it and drop the handlers on close.
|
|
1724
2305
|
const onOrphanError = () => undefined;
|
|
1725
2306
|
const onOrphanClose = () => {
|
|
1726
2307
|
ws.removeEventListener('error', onOrphanError);
|
|
@@ -1731,8 +2312,7 @@ function createWebSocket(wsUrl, timeoutMs = WS_TIMEOUT) {
|
|
|
1731
2312
|
ws.close();
|
|
1732
2313
|
}
|
|
1733
2314
|
else {
|
|
1734
|
-
//
|
|
1735
|
-
// Just remove our internal listener; don't touch the socket.
|
|
2315
|
+
// Delivered — the consumer owns it; only drop our listener.
|
|
1736
2316
|
ws.removeEventListener('open', onOpen);
|
|
1737
2317
|
}
|
|
1738
2318
|
};
|
|
@@ -2366,10 +2946,10 @@ class SignallingService extends SubService {
|
|
|
2366
2946
|
Logger.log('Start Getting Region');
|
|
2367
2947
|
return this.regionsPingService.getFastest().pipe(take(1));
|
|
2368
2948
|
}
|
|
2369
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
2370
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
2949
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SignallingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2950
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SignallingService, providedIn: 'root' }); }
|
|
2371
2951
|
}
|
|
2372
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
2952
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SignallingService, decorators: [{
|
|
2373
2953
|
type: Injectable,
|
|
2374
2954
|
args: [{ providedIn: 'root' }]
|
|
2375
2955
|
}], ctorParameters: () => [] });
|
|
@@ -2784,10 +3364,10 @@ class VideoService extends SubService {
|
|
|
2784
3364
|
this.armGestureRetry(audio);
|
|
2785
3365
|
}
|
|
2786
3366
|
}
|
|
2787
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
2788
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
3367
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: VideoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3368
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: VideoService, providedIn: 'root' }); }
|
|
2789
3369
|
}
|
|
2790
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
3370
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: VideoService, decorators: [{
|
|
2791
3371
|
type: Injectable,
|
|
2792
3372
|
args: [{ providedIn: 'root' }]
|
|
2793
3373
|
}], ctorParameters: () => [] });
|
|
@@ -3453,10 +4033,10 @@ class WebRtcPlayerService extends SubService {
|
|
|
3453
4033
|
Logger.error("Couldn't create answer", e);
|
|
3454
4034
|
}
|
|
3455
4035
|
}
|
|
3456
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
3457
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
4036
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: WebRtcPlayerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4037
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: WebRtcPlayerService, providedIn: 'root' }); }
|
|
3458
4038
|
}
|
|
3459
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
4039
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: WebRtcPlayerService, decorators: [{
|
|
3460
4040
|
type: Injectable,
|
|
3461
4041
|
args: [{ providedIn: 'root' }]
|
|
3462
4042
|
}], ctorParameters: () => [] });
|
|
@@ -3626,10 +4206,10 @@ class StreamAdoptionService {
|
|
|
3626
4206
|
this.webRtc.adopt(parked.pc, parked.dc, parked.stream, parked.config ?? {}, parked.dcBuffer);
|
|
3627
4207
|
return true;
|
|
3628
4208
|
}
|
|
3629
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
3630
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
4209
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StreamAdoptionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4210
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StreamAdoptionService, providedIn: 'root' }); }
|
|
3631
4211
|
}
|
|
3632
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
4212
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StreamAdoptionService, decorators: [{
|
|
3633
4213
|
type: Injectable,
|
|
3634
4214
|
args: [{ providedIn: 'root' }]
|
|
3635
4215
|
}] });
|
|
@@ -3697,10 +4277,10 @@ class UnrealCallbackService {
|
|
|
3697
4277
|
return observable;
|
|
3698
4278
|
});
|
|
3699
4279
|
}
|
|
3700
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
3701
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
4280
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealCallbackService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4281
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealCallbackService, providedIn: 'root' }); }
|
|
3702
4282
|
}
|
|
3703
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
4283
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealCallbackService, decorators: [{
|
|
3704
4284
|
type: Injectable,
|
|
3705
4285
|
args: [{ providedIn: 'root' }]
|
|
3706
4286
|
}] });
|
|
@@ -3817,10 +4397,10 @@ class UnrealCommunicatorService extends SubService {
|
|
|
3817
4397
|
requestQualityControl() {
|
|
3818
4398
|
this.sendInputData(new Uint8Array([MessageType.RequestQualityControl]).buffer);
|
|
3819
4399
|
}
|
|
3820
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
3821
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
4400
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealCommunicatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4401
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealCommunicatorService, providedIn: 'root' }); }
|
|
3822
4402
|
}
|
|
3823
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
4403
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealCommunicatorService, decorators: [{
|
|
3824
4404
|
type: Injectable,
|
|
3825
4405
|
args: [{ providedIn: 'root' }]
|
|
3826
4406
|
}], ctorParameters: () => [] });
|
|
@@ -3834,10 +4414,10 @@ class UnrealErrorModalComponent {
|
|
|
3834
4414
|
close() {
|
|
3835
4415
|
this.#dialogRef.close();
|
|
3836
4416
|
}
|
|
3837
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
3838
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.
|
|
4417
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealErrorModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4418
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.3", type: UnrealErrorModalComponent, isStandalone: true, selector: "app-unreal-error-modal", ngImport: i0, template: "<div class=\"unreal-modal\">\n <header class=\"unreal-modal__header\">\n <div\n [attr.data-testid]=\"'unreal-error-header-title'\"\n class=\"unreal-modal__title\"\n >\n Warning\n </div>\n </header>\n <div class=\"unreal-modal__body\">\n <div>{{ dialogData.content }}</div>\n </div>\n <div class=\"unreal-modal__footer\">\n <app-unreal-button (clicked)=\"close()\">Ok</app-unreal-button>\n </div>\n</div>\n", styles: [".unreal-modal{--unrealModalWidth: 422px;--unrealModalMaxWidth: calc(100% - 16px) ;--unrealModalMaxHeight: 80vh;--unrealModalBg: var(--src-surface-container-main, #fff);--unrealModalBoxShadow: 0 16px 36px 4px var(--src-shadow-hard, rgba(71, 85, 105, .24)), 0 1px 4px 0 var(--src-shadow-light, rgba(148, 163, 184, .16));--unrealModalBorderRadius: var(--src-layout-radius-const-rounded-md, 12px);--unrealModalTitleSize: var(--src-font-size-base, 16px);--unrealModalTitleLineHeight: var(--src-font-line-base, 24px);--unrealModalTitleColor: var(--src-text-body-main, #111827);--unrealModalBodyPadding: var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-2xl, 32px) var(--src-layout-padding-const-xl, 24px);--unrealModalTitleBorder: none;--unrealModalFooterBorder: 1px solid var(--src-border-container-light, rgba(148, 163, 184, .16));display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto;width:var(--unrealModalWidth);max-width:var(--unrealModalMaxWidth);max-height:var(--unrealModalMaxHeight);margin:auto;background-color:var(--unrealModalBg);border-radius:var(--unrealModalBorderRadius);box-shadow:var(--unrealModalBoxShadow);color:var(--src-text-body-secondary, #4b5563);font-family:var(--src-font-family-header, Inter);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:var(--src-font-line-sm, 20px)}.unreal-modal .unreal-modal__header{position:relative;display:flex;padding:0;width:100%;border-bottom:var(--unrealModalTitleBorder)}.unreal-modal .unreal-modal__body{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);gap:var(--src-layout-gap-const-md, 12px);padding:var(--unrealModalBodyPadding);overflow:auto;scrollbar-width:thin;scrollbar-color:var(--src-border-container-basic, rgba(148, 163, 184, .24)) transparent}.unreal-modal .unreal-modal__body .unreal-modal__title{grid-column:1/-1}.unreal-modal .unreal-modal__body::-webkit-scrollbar{width:4px}.unreal-modal .unreal-modal__body::-webkit-scrollbar-track{background:transparent}.unreal-modal .unreal-modal__body::-webkit-scrollbar-thumb{background-color:var(--src-border-container-basic, rgba(148, 163, 184, .24));border-radius:10px}.unreal-modal .unreal-modal__footer{display:flex;justify-content:flex-end;align-items:center;padding:var(--src-layout-padding-const-md, 12px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px);width:100%;border-top:var(--unrealModalFooterBorder);gap:var(--src-layout-gap-const-sm, 8px)}.unreal-modal .unreal-modal__title{font-size:var(--unrealModalTitleSize);font-weight:600;line-height:var(--unrealModalTitleLineHeight);color:var(--unrealModalTitleColor);word-break:break-word}.unreal-modal .unreal-modal__header{padding:16px 24px 0}\n"], dependencies: [{ kind: "component", type: UnrealButtonComponent, selector: "app-unreal-button", inputs: ["type", "weight", "size", "fullWidth", "isDisabled", "data-testid", "ariaLabel"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3839
4419
|
}
|
|
3840
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
4420
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealErrorModalComponent, decorators: [{
|
|
3841
4421
|
type: Component,
|
|
3842
4422
|
args: [{ selector: 'app-unreal-error-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent], template: "<div class=\"unreal-modal\">\n <header class=\"unreal-modal__header\">\n <div\n [attr.data-testid]=\"'unreal-error-header-title'\"\n class=\"unreal-modal__title\"\n >\n Warning\n </div>\n </header>\n <div class=\"unreal-modal__body\">\n <div>{{ dialogData.content }}</div>\n </div>\n <div class=\"unreal-modal__footer\">\n <app-unreal-button (clicked)=\"close()\">Ok</app-unreal-button>\n </div>\n</div>\n", styles: [".unreal-modal{--unrealModalWidth: 422px;--unrealModalMaxWidth: calc(100% - 16px) ;--unrealModalMaxHeight: 80vh;--unrealModalBg: var(--src-surface-container-main, #fff);--unrealModalBoxShadow: 0 16px 36px 4px var(--src-shadow-hard, rgba(71, 85, 105, .24)), 0 1px 4px 0 var(--src-shadow-light, rgba(148, 163, 184, .16));--unrealModalBorderRadius: var(--src-layout-radius-const-rounded-md, 12px);--unrealModalTitleSize: var(--src-font-size-base, 16px);--unrealModalTitleLineHeight: var(--src-font-line-base, 24px);--unrealModalTitleColor: var(--src-text-body-main, #111827);--unrealModalBodyPadding: var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-2xl, 32px) var(--src-layout-padding-const-xl, 24px);--unrealModalTitleBorder: none;--unrealModalFooterBorder: 1px solid var(--src-border-container-light, rgba(148, 163, 184, .16));display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto;width:var(--unrealModalWidth);max-width:var(--unrealModalMaxWidth);max-height:var(--unrealModalMaxHeight);margin:auto;background-color:var(--unrealModalBg);border-radius:var(--unrealModalBorderRadius);box-shadow:var(--unrealModalBoxShadow);color:var(--src-text-body-secondary, #4b5563);font-family:var(--src-font-family-header, Inter);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:var(--src-font-line-sm, 20px)}.unreal-modal .unreal-modal__header{position:relative;display:flex;padding:0;width:100%;border-bottom:var(--unrealModalTitleBorder)}.unreal-modal .unreal-modal__body{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);gap:var(--src-layout-gap-const-md, 12px);padding:var(--unrealModalBodyPadding);overflow:auto;scrollbar-width:thin;scrollbar-color:var(--src-border-container-basic, rgba(148, 163, 184, .24)) transparent}.unreal-modal .unreal-modal__body .unreal-modal__title{grid-column:1/-1}.unreal-modal .unreal-modal__body::-webkit-scrollbar{width:4px}.unreal-modal .unreal-modal__body::-webkit-scrollbar-track{background:transparent}.unreal-modal .unreal-modal__body::-webkit-scrollbar-thumb{background-color:var(--src-border-container-basic, rgba(148, 163, 184, .24));border-radius:10px}.unreal-modal .unreal-modal__footer{display:flex;justify-content:flex-end;align-items:center;padding:var(--src-layout-padding-const-md, 12px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px);width:100%;border-top:var(--unrealModalFooterBorder);gap:var(--src-layout-gap-const-sm, 8px)}.unreal-modal .unreal-modal__title{font-size:var(--unrealModalTitleSize);font-weight:600;line-height:var(--unrealModalTitleLineHeight);color:var(--unrealModalTitleColor);word-break:break-word}.unreal-modal .unreal-modal__header{padding:16px 24px 0}\n"] }]
|
|
3843
4423
|
}] });
|
|
@@ -4233,10 +4813,10 @@ class UnrealEffects {
|
|
|
4233
4813
|
// Fails silently if cross-origin
|
|
4234
4814
|
}
|
|
4235
4815
|
}
|
|
4236
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
4237
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
4816
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealEffects, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4817
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealEffects }); }
|
|
4238
4818
|
}
|
|
4239
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
4819
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealEffects, decorators: [{
|
|
4240
4820
|
type: Injectable
|
|
4241
4821
|
}] });
|
|
4242
4822
|
|
|
@@ -4388,10 +4968,9 @@ const floatToSmoothPercents = () => (source) => source.pipe(timestamp(), startWi
|
|
|
4388
4968
|
* Smoothly interpolates from `start` to `end` over `duration`ms using the
|
|
4389
4969
|
* animation frame scheduler. Completes when the transition finishes.
|
|
4390
4970
|
*
|
|
4391
|
-
*
|
|
4392
|
-
*
|
|
4393
|
-
*
|
|
4394
|
-
* Not exported: internal to `floatToSmoothPercents`.
|
|
4971
|
+
* Deliberately local. The version this was forked from never completed — it
|
|
4972
|
+
* lacked `takeWhile(... < 1, true)` — which would deadlock the `concatMap`
|
|
4973
|
+
* above. Not exported: internal to `floatToSmoothPercents`.
|
|
4395
4974
|
*/
|
|
4396
4975
|
const smoothTransition = (start, end, duration) => {
|
|
4397
4976
|
const startTime = animationFrameScheduler.now();
|
|
@@ -4753,10 +5332,10 @@ class AFKService extends SubService {
|
|
|
4753
5332
|
}
|
|
4754
5333
|
}, 1000);
|
|
4755
5334
|
}
|
|
4756
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
4757
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
5335
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AFKService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5336
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AFKService, providedIn: 'root' }); }
|
|
4758
5337
|
}
|
|
4759
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
5338
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AFKService, decorators: [{
|
|
4760
5339
|
type: Injectable,
|
|
4761
5340
|
args: [{ providedIn: 'root' }]
|
|
4762
5341
|
}], ctorParameters: () => [] });
|
|
@@ -4806,10 +5385,10 @@ class LoadingProgressService {
|
|
|
4806
5385
|
// `switchMap` cancels the inner subscription on every visibility change
|
|
4807
5386
|
// so stale emissions can't leak through.
|
|
4808
5387
|
#boundedProgress$;
|
|
4809
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
4810
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
5388
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: LoadingProgressService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5389
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: LoadingProgressService, providedIn: 'root' }); }
|
|
4811
5390
|
}
|
|
4812
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
5391
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: LoadingProgressService, decorators: [{
|
|
4813
5392
|
type: Injectable,
|
|
4814
5393
|
args: [{ providedIn: 'root' }]
|
|
4815
5394
|
}] });
|
|
@@ -4895,10 +5474,10 @@ class FreezeFrameService extends SubService {
|
|
|
4895
5474
|
progress: 1,
|
|
4896
5475
|
}));
|
|
4897
5476
|
}
|
|
4898
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
4899
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
5477
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FreezeFrameService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5478
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FreezeFrameService, providedIn: 'root' }); }
|
|
4900
5479
|
}
|
|
4901
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
5480
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FreezeFrameService, decorators: [{
|
|
4902
5481
|
type: Injectable,
|
|
4903
5482
|
args: [{ providedIn: 'root' }]
|
|
4904
5483
|
}], ctorParameters: () => [] });
|
|
@@ -5050,19 +5629,21 @@ class FileReceiverService extends SubService {
|
|
|
5050
5629
|
this.reset();
|
|
5051
5630
|
}
|
|
5052
5631
|
}
|
|
5053
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
5054
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
5632
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FileReceiverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5633
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FileReceiverService, providedIn: 'root' }); }
|
|
5055
5634
|
}
|
|
5056
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
5635
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FileReceiverService, decorators: [{
|
|
5057
5636
|
type: Injectable,
|
|
5058
5637
|
args: [{ providedIn: 'root' }]
|
|
5059
5638
|
}], ctorParameters: () => [] });
|
|
5060
5639
|
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5640
|
+
/**
|
|
5641
|
+
* Matches the normalisation the old `where()` predicate applied to both sides:
|
|
5642
|
+
* trim, collapse space runs to `_`, lowercase.
|
|
5643
|
+
*/
|
|
5644
|
+
const normalizeCommand = (value) => String(value).trim().replace(/ +/gi, '_').toLowerCase();
|
|
5645
|
+
/** Commands whose arrival is not worth a console line. */
|
|
5646
|
+
const FILTERED_LOG_COMMANDS = new Set(['onChangeSequence'].map(normalizeCommand));
|
|
5066
5647
|
class AggregatorService extends SubService {
|
|
5067
5648
|
constructor() {
|
|
5068
5649
|
super();
|
|
@@ -5149,7 +5730,11 @@ class AggregatorService extends SubService {
|
|
|
5149
5730
|
});
|
|
5150
5731
|
}
|
|
5151
5732
|
showMessageFromUnreal(json) {
|
|
5152
|
-
|
|
5733
|
+
// The `undefined` check is redundant while the set holds only real command
|
|
5734
|
+
// names, but `where()` ignored undefined criteria outright — keep it so an
|
|
5735
|
+
// entry literally named 'undefined' could never start matching.
|
|
5736
|
+
if (json?.command !== undefined &&
|
|
5737
|
+
FILTERED_LOG_COMMANDS.has(normalizeCommand(json.command))) {
|
|
5153
5738
|
return;
|
|
5154
5739
|
}
|
|
5155
5740
|
Logger.colored(...COLOR_CODES.FROM_UNREAL, json);
|
|
@@ -5232,10 +5817,10 @@ class AggregatorService extends SubService {
|
|
|
5232
5817
|
Logger.warn(`unrecognized data received, packet ID ${view[0]}`);
|
|
5233
5818
|
}
|
|
5234
5819
|
}
|
|
5235
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
5236
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
5820
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AggregatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5821
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AggregatorService, providedIn: 'root' }); }
|
|
5237
5822
|
}
|
|
5238
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
5823
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AggregatorService, decorators: [{
|
|
5239
5824
|
type: Injectable,
|
|
5240
5825
|
args: [{ providedIn: 'root' }]
|
|
5241
5826
|
}], ctorParameters: () => [] });
|
|
@@ -5396,10 +5981,10 @@ class ConsoleExtensionsService extends SubService {
|
|
|
5396
5981
|
Logger.info('emitCommand(command) => send command to Unreal Engine.');
|
|
5397
5982
|
Logger.info('stressTest({iterations}) => hammer reconnect: repeatedly drop DC/PC and assert recovery.');
|
|
5398
5983
|
}
|
|
5399
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
5400
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
5984
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ConsoleExtensionsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5985
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ConsoleExtensionsService, providedIn: 'root' }); }
|
|
5401
5986
|
}
|
|
5402
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
5987
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ConsoleExtensionsService, decorators: [{
|
|
5403
5988
|
type: Injectable,
|
|
5404
5989
|
args: [{ providedIn: 'root' }]
|
|
5405
5990
|
}], ctorParameters: () => [] });
|
|
@@ -5413,30 +5998,48 @@ const RESIZE_DEBOUNCE_MS = 300;
|
|
|
5413
5998
|
const FUNCTION_KEY_MIN = 112;
|
|
5414
5999
|
const FUNCTION_KEY_MAX = 123;
|
|
5415
6000
|
const TAB_KEY_CODE = 9;
|
|
6001
|
+
// VK_LEFT..VK_DOWN. Held down, these scroll the page while they steer the
|
|
6002
|
+
// camera, so they belong with the keys `suppressBrowserKeys` neutralises.
|
|
6003
|
+
const ARROW_KEY_MIN = 37;
|
|
6004
|
+
const ARROW_KEY_MAX = 40;
|
|
6005
|
+
/** Elements that own the keyboard while focused — never forward to the stream. */
|
|
6006
|
+
const TEXT_ENTRY_SELECTOR = 'input, textarea, select, [contenteditable]:not([contenteditable="false"])';
|
|
5416
6007
|
class InputService extends SubService {
|
|
5417
6008
|
constructor() {
|
|
5418
6009
|
super();
|
|
5419
6010
|
this.commandsSender = inject(UnrealCommunicatorService);
|
|
5420
|
-
|
|
6011
|
+
// The service, not its value: `isDevMode` is a getter over localStorage, and
|
|
6012
|
+
// `setDevMode()` is documented as callable from the console at runtime.
|
|
6013
|
+
this.devModeService = inject(DevModeService);
|
|
5421
6014
|
this.videoService = inject(VideoService);
|
|
5422
6015
|
this.unrealConfig = inject(UNREAL_CONFIG, { optional: true });
|
|
6016
|
+
// Physical key names (`KeyboardEvent.code`), which is what the allow-list is
|
|
6017
|
+
// matched against. The numpad digits are deliberately absent: with NumLock
|
|
6018
|
+
// off they *are* the arrows, but the browser reports them under their own
|
|
6019
|
+
// `code`, so enabling them here would forward a second set of arrow keys.
|
|
6020
|
+
// A consumer that wants them passes them to `useKeyboardKeys`.
|
|
5423
6021
|
this.defaultKeys = [
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
6022
|
+
'KeyW',
|
|
6023
|
+
'KeyS',
|
|
6024
|
+
'KeyA',
|
|
6025
|
+
'KeyD',
|
|
6026
|
+
'ArrowUp',
|
|
6027
|
+
'ArrowDown',
|
|
6028
|
+
'ArrowLeft',
|
|
6029
|
+
'ArrowRight',
|
|
6030
|
+
'NumpadAdd',
|
|
6031
|
+
'NumpadSubtract',
|
|
6032
|
+
// Both Control keys. Only `ControlRight` was ever declared here, but the
|
|
6033
|
+
// numeric allow-list resolved 17 to `'ControlLeft'`, so the left one is what
|
|
6034
|
+
// actually reached the engine — dropping it now would be a regression for
|
|
6035
|
+
// the more commonly pressed of the two.
|
|
6036
|
+
'ControlLeft',
|
|
6037
|
+
'ControlRight',
|
|
6038
|
+
'Equal',
|
|
6039
|
+
'Minus',
|
|
6040
|
+
'NumpadDecimal',
|
|
5438
6041
|
];
|
|
5439
|
-
this.availableKeys = this.defaultKeys;
|
|
6042
|
+
this.availableKeys = new Set(this.defaultKeys);
|
|
5440
6043
|
this.options = InputOptions;
|
|
5441
6044
|
this.reInit$ = new Subject();
|
|
5442
6045
|
this.deactivatedVideoTrigger$ = NEVER;
|
|
@@ -5453,6 +6056,12 @@ class InputService extends SubService {
|
|
|
5453
6056
|
this.fingerIds = new Map();
|
|
5454
6057
|
this.maxByteValue = 255;
|
|
5455
6058
|
this.fingers = [...INITIAL_FINGER_IDS];
|
|
6059
|
+
// Virtual-key codes for which a KeyDown has been sent and no KeyUp yet. This
|
|
6060
|
+
// is the sole gate on KeyUp, which makes the pairing an invariant instead of
|
|
6061
|
+
// something the filters have to agree on twice: a key the engine was never
|
|
6062
|
+
// told about cannot be released, and a key it was told about is always
|
|
6063
|
+
// released — including when the browser never delivers the `keyup` at all.
|
|
6064
|
+
this.heldKeys = new Set();
|
|
5456
6065
|
// Reusable wire buffers. Input events fire at up to ~60 Hz; the data channel
|
|
5457
6066
|
// copies the bytes synchronously on sending (RTCDataChannel.send), so a single
|
|
5458
6067
|
// buffer per message shape is safe and avoids per-event allocation/GC churn.
|
|
@@ -5485,8 +6094,17 @@ class InputService extends SubService {
|
|
|
5485
6094
|
.pipe(filter(() => !!this.video), takeUntil$1(this.destroy$))
|
|
5486
6095
|
.subscribe(() => this.setup());
|
|
5487
6096
|
}
|
|
6097
|
+
/**
|
|
6098
|
+
* Replaces the forwarded-key allow-list. Takes physical key names
|
|
6099
|
+
* (`KeyboardEvent.code`) such as `'KeyW'` or `'BracketLeft'`.
|
|
6100
|
+
*
|
|
6101
|
+
* Legacy numeric `keyCode` values are still accepted and converted, but they
|
|
6102
|
+
* cannot express every key: `InvertedKeyMap` is many-to-one, so 37 resolves
|
|
6103
|
+
* to `'ArrowLeft'` and 17 to `'ControlLeft'`, and `'Numpad4'`/`'ControlRight'`
|
|
6104
|
+
* are unreachable through the numeric form. Pass names.
|
|
6105
|
+
*/
|
|
5488
6106
|
useKeyboardKeys(keys) {
|
|
5489
|
-
this.availableKeys = keys;
|
|
6107
|
+
this.availableKeys = new Set(keys.map((key) => (typeof key === 'number' ? InvertedKeyMap[key] : key)));
|
|
5490
6108
|
}
|
|
5491
6109
|
get video() {
|
|
5492
6110
|
return this.videoService.video;
|
|
@@ -5501,6 +6119,10 @@ class InputService extends SubService {
|
|
|
5501
6119
|
// Reset touch state to prevent stale identifiers across sessions
|
|
5502
6120
|
this.fingerIds.clear();
|
|
5503
6121
|
this.fingers = [...INITIAL_FINGER_IDS];
|
|
6122
|
+
// Same for the key registry: a key held across a reconnect belongs to the
|
|
6123
|
+
// previous engine session, and releasing it into the new one is worse than
|
|
6124
|
+
// dropping it.
|
|
6125
|
+
this.heldKeys.clear();
|
|
5504
6126
|
merge(fromResizeObserver(video), this.actions$.pipe(ofType(videoAdaptedToContainer)))
|
|
5505
6127
|
.pipe(debounceTime$1(RESIZE_DEBOUNCE_MS), takeUntil$1(this.deactivatedVideoTrigger$))
|
|
5506
6128
|
.subscribe(() => this.setupNormalizeAndQuantize(video));
|
|
@@ -5588,9 +6210,17 @@ class InputService extends SubService {
|
|
|
5588
6210
|
fromEvent(window, 'blur')
|
|
5589
6211
|
.pipe(filter(() => !!video), takeUntil$1(this.deactivatedVideoTrigger$))
|
|
5590
6212
|
.subscribe(() => this.releaseMouseButtons(255, 0, 0));
|
|
6213
|
+
// Deliberately *not* gated on `deactivatedVideoTrigger$`: that trigger
|
|
6214
|
+
// includes the visibility-hidden event, so a subscription behind it is torn
|
|
6215
|
+
// down by the very event this one has to react to. `reInit$` alone is
|
|
6216
|
+
// enough to avoid stacking duplicates across `setup()` calls, since
|
|
6217
|
+
// `setup()` fires it before it gets here.
|
|
6218
|
+
merge(fromEvent(window, 'blur'), fromEvent(document, 'visibilitychange').pipe(filter(() => document.visibilityState === 'hidden')))
|
|
6219
|
+
.pipe(takeUntil$1(merge(this.reInit$, this.destroy$)))
|
|
6220
|
+
.subscribe(() => this.releaseKeys());
|
|
5591
6221
|
this.registerMouseEnterAndLeaveEvents(video);
|
|
5592
6222
|
this.registerHoveringMouseEvents(video);
|
|
5593
|
-
this.registerKeyboardEvents(
|
|
6223
|
+
this.registerKeyboardEvents();
|
|
5594
6224
|
this.registerTouchEvents(video);
|
|
5595
6225
|
}
|
|
5596
6226
|
getTouchPositionWithOffset({ clientX, clientY }) {
|
|
@@ -5812,62 +6442,108 @@ class InputService extends SubService {
|
|
|
5812
6442
|
this.releaseMouseButtons(e.buttons, e.offsetX, e.offsetY);
|
|
5813
6443
|
});
|
|
5814
6444
|
}
|
|
5815
|
-
|
|
5816
|
-
|
|
6445
|
+
/**
|
|
6446
|
+
* Keys whose default browser action fights the stream: the function keys
|
|
6447
|
+
* (F5 reloads mid-session), Tab (moves focus out of the player) and the
|
|
6448
|
+
* arrows (scroll the page while they steer the camera).
|
|
6449
|
+
*
|
|
6450
|
+
* Takes the *resolved* virtual-key code rather than `event.code`, so a numpad
|
|
6451
|
+
* key acting as an arrow with NumLock off is caught as well.
|
|
6452
|
+
*/
|
|
6453
|
+
isBrowserKey(keyCode) {
|
|
5817
6454
|
return ((keyCode >= FUNCTION_KEY_MIN && keyCode <= FUNCTION_KEY_MAX) ||
|
|
6455
|
+
(keyCode >= ARROW_KEY_MIN && keyCode <= ARROW_KEY_MAX) ||
|
|
5818
6456
|
keyCode === TAB_KEY_CODE);
|
|
5819
6457
|
}
|
|
5820
6458
|
/**
|
|
5821
|
-
* The key code Unreal expects
|
|
6459
|
+
* The key code Unreal expects — the Windows virtual-key code — or `null` when
|
|
6460
|
+
* the event carries no key worth forwarding.
|
|
5822
6461
|
*
|
|
5823
|
-
* `
|
|
5824
|
-
*
|
|
5825
|
-
*
|
|
5826
|
-
* `KeyboardNumericCode` is keyed by `e.code` and holds the virtual-key value,
|
|
5827
|
-
* so it resolves the same number on every browser; a no-op on Chrome.
|
|
6462
|
+
* `KeyboardNumericCode` covers only the keys whose `event.keyCode` cannot be
|
|
6463
|
+
* trusted; everything else, the numpad included, falls through to the value
|
|
6464
|
+
* the browser resolved.
|
|
5828
6465
|
*
|
|
5829
|
-
*
|
|
5830
|
-
*
|
|
6466
|
+
* Returns `null` for an IME composition — `event.code` still names the
|
|
6467
|
+
* physical key there, so the keystrokes would otherwise reach the engine as
|
|
6468
|
+
* camera movement — and for a `keyCode` of 0, which no engine key uses.
|
|
5831
6469
|
*/
|
|
5832
6470
|
getKeyCode(e) {
|
|
5833
|
-
if (e.keyCode ===
|
|
5834
|
-
return
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
6471
|
+
if (e.keyCode === IME_PROCESS_KEY) {
|
|
6472
|
+
return null;
|
|
6473
|
+
}
|
|
6474
|
+
const keyCode = KeyboardNumericCode[e.code] ??
|
|
6475
|
+
e.keyCode;
|
|
6476
|
+
return keyCode || null;
|
|
6477
|
+
}
|
|
6478
|
+
/**
|
|
6479
|
+
* True while a focused element owns the keyboard. Read off `composedPath()`
|
|
6480
|
+
* rather than `event.target`: retargeting reports the host element for an
|
|
6481
|
+
* `<input>` inside a shadow root, so a `target`-based check never fires in an
|
|
6482
|
+
* app built from web components.
|
|
6483
|
+
*/
|
|
6484
|
+
isTextEntryTarget(e) {
|
|
6485
|
+
const target = e.composedPath()[0] ?? e.target;
|
|
6486
|
+
return target instanceof Element && !!target.closest(TEXT_ENTRY_SELECTOR);
|
|
6487
|
+
}
|
|
6488
|
+
/** True when `event.code` is on the allow-list, or dev mode waives it. */
|
|
6489
|
+
isKeyAllowed(e) {
|
|
6490
|
+
if (this.availableKeys.has(e.code)) {
|
|
6491
|
+
return true;
|
|
6492
|
+
}
|
|
6493
|
+
if (!this.devModeService.isDevMode) {
|
|
6494
|
+
return false;
|
|
6495
|
+
}
|
|
6496
|
+
// Once per press, not once per keydown/keyup/keypress and not on autorepeat.
|
|
6497
|
+
if (e.type === 'keydown' && !e.repeat) {
|
|
6498
|
+
Logger.warn('Code=>', e.code, 'Keyboard event is not filtered in DEV Mode. App may behave inappropriately!');
|
|
6499
|
+
}
|
|
6500
|
+
return true;
|
|
6501
|
+
}
|
|
6502
|
+
sendKeyUp(keyCode) {
|
|
6503
|
+
const keyUp = this.keyUpBytes;
|
|
6504
|
+
keyUp[0] = MessageType.KeyUp;
|
|
6505
|
+
keyUp[1] = keyCode;
|
|
6506
|
+
this.sendInputData(keyUp.buffer);
|
|
5855
6507
|
}
|
|
5856
|
-
|
|
5857
|
-
|
|
6508
|
+
/**
|
|
6509
|
+
* Releases everything the engine still believes is held. Needed because a
|
|
6510
|
+
* `keyup` is not guaranteed to arrive: the window can lose focus to a browser
|
|
6511
|
+
* dialog or another tab first, and then the engine keeps moving the camera
|
|
6512
|
+
* forever.
|
|
6513
|
+
*/
|
|
6514
|
+
releaseKeys() {
|
|
6515
|
+
for (const keyCode of this.heldKeys) {
|
|
6516
|
+
this.sendKeyUp(keyCode);
|
|
6517
|
+
}
|
|
6518
|
+
this.heldKeys.clear();
|
|
6519
|
+
}
|
|
6520
|
+
registerKeyboardEvents() {
|
|
5858
6521
|
fromEvent(document, 'keydown')
|
|
5859
6522
|
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
5860
6523
|
.subscribe((e) => {
|
|
5861
|
-
|
|
6524
|
+
// A focused field owns the key outright — no forwarding and no
|
|
6525
|
+
// `preventDefault`, or Tab could not move between inputs.
|
|
6526
|
+
if (this.isTextEntryTarget(e)) {
|
|
5862
6527
|
return;
|
|
5863
6528
|
}
|
|
5864
|
-
const isCtrlOrCommand = e.ctrlKey || e.metaKey;
|
|
5865
|
-
// Normalised first: on Firefox the raw `e.keyCode` for these keys is 61
|
|
5866
|
-
// and 173, so comparing it left browser zoom to reach the engine too.
|
|
5867
6529
|
const keyCode = this.getKeyCode(e);
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
6530
|
+
if (keyCode === null) {
|
|
6531
|
+
return;
|
|
6532
|
+
}
|
|
6533
|
+
// Ahead of the allow-list on purpose. None of the browser keys are
|
|
6534
|
+
// forwarded, so a check that sits behind the allow-list can never run,
|
|
6535
|
+
// which is what made `suppressBrowserKeys` a no-op.
|
|
6536
|
+
if (this.options.suppressBrowserKeys && this.isBrowserKey(keyCode)) {
|
|
6537
|
+
e.preventDefault();
|
|
6538
|
+
}
|
|
6539
|
+
if (!this.isKeyAllowed(e)) {
|
|
6540
|
+
return;
|
|
6541
|
+
}
|
|
6542
|
+
// A browser shortcut is in flight (Ctrl+W closes the tab, Ctrl+S opens
|
|
6543
|
+
// a dialog, Ctrl+= zooms). The browser acts on it regardless, so the
|
|
6544
|
+
// engine must not also treat it as gameplay input. Modifier keys are
|
|
6545
|
+
// exempt: their own keydown already reports themselves as pressed.
|
|
6546
|
+
if ((e.ctrlKey || e.metaKey) && !MODIFIER_KEY_CODES.has(e.code)) {
|
|
5871
6547
|
return;
|
|
5872
6548
|
}
|
|
5873
6549
|
const keyDown = this.keyDownBytes;
|
|
@@ -5875,38 +6551,46 @@ class InputService extends SubService {
|
|
|
5875
6551
|
keyDown[1] = keyCode;
|
|
5876
6552
|
keyDown[2] = Number(e.repeat);
|
|
5877
6553
|
this.sendInputData(keyDown.buffer);
|
|
6554
|
+
this.heldKeys.add(keyCode);
|
|
5878
6555
|
// Backspace isn't a keypress in JS, but UE4 text-entry fields need it
|
|
5879
6556
|
// to delete characters.
|
|
5880
|
-
if (
|
|
6557
|
+
if (keyCode === SpecialKeyCodes.BackSpace) {
|
|
5881
6558
|
const data = this.keyPressView;
|
|
5882
6559
|
data.setUint8(0, MessageType.KeyPress);
|
|
5883
6560
|
data.setUint16(1, SpecialKeyCodes.BackSpace, true);
|
|
5884
6561
|
this.sendInputData(data.buffer);
|
|
5885
6562
|
}
|
|
5886
|
-
if (this.options.suppressBrowserKeys &&
|
|
5887
|
-
this.isKeyCodeBrowserKey(e.keyCode)) {
|
|
5888
|
-
e.preventDefault();
|
|
5889
|
-
}
|
|
5890
6563
|
});
|
|
5891
6564
|
fromEvent(document, 'keyup')
|
|
5892
6565
|
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
5893
6566
|
.subscribe((e) => {
|
|
5894
|
-
|
|
6567
|
+
const keyCode = this.getKeyCode(e);
|
|
6568
|
+
if (keyCode === null) {
|
|
5895
6569
|
return;
|
|
5896
6570
|
}
|
|
5897
|
-
const keyUp = this.keyUpBytes;
|
|
5898
|
-
keyUp[0] = MessageType.KeyUp;
|
|
5899
|
-
keyUp[1] = this.getKeyCode(e);
|
|
5900
|
-
this.sendInputData(keyUp.buffer);
|
|
5901
6571
|
if (this.options.suppressBrowserKeys &&
|
|
5902
|
-
this.
|
|
6572
|
+
this.isBrowserKey(keyCode) &&
|
|
6573
|
+
!this.isTextEntryTarget(e)) {
|
|
5903
6574
|
e.preventDefault();
|
|
5904
6575
|
}
|
|
6576
|
+
// The registry is the only gate here. Re-running the allow-list and the
|
|
6577
|
+
// focus check would let their state drift between press and release —
|
|
6578
|
+
// press over the video, release with a dialog focused, and the engine
|
|
6579
|
+
// never hears the key came up.
|
|
6580
|
+
if (!this.heldKeys.delete(keyCode)) {
|
|
6581
|
+
return;
|
|
6582
|
+
}
|
|
6583
|
+
this.sendKeyUp(keyCode);
|
|
5905
6584
|
});
|
|
5906
6585
|
fromEvent(document, 'keypress')
|
|
5907
6586
|
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
5908
6587
|
.subscribe((e) => {
|
|
5909
|
-
if (
|
|
6588
|
+
if (this.isTextEntryTarget(e) || !this.isKeyAllowed(e)) {
|
|
6589
|
+
return;
|
|
6590
|
+
}
|
|
6591
|
+
// Deprecated event: the payload is a character, so an IME composition
|
|
6592
|
+
// or a key with no character produces nothing to send.
|
|
6593
|
+
if (e.keyCode === IME_PROCESS_KEY || !e.charCode) {
|
|
5910
6594
|
return;
|
|
5911
6595
|
}
|
|
5912
6596
|
const data = this.keyPressView;
|
|
@@ -5915,10 +6599,10 @@ class InputService extends SubService {
|
|
|
5915
6599
|
this.sendInputData(data.buffer);
|
|
5916
6600
|
});
|
|
5917
6601
|
}
|
|
5918
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
5919
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
6602
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: InputService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
6603
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: InputService, providedIn: 'root' }); }
|
|
5920
6604
|
}
|
|
5921
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
6605
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: InputService, decorators: [{
|
|
5922
6606
|
type: Injectable,
|
|
5923
6607
|
args: [{ providedIn: 'root' }]
|
|
5924
6608
|
}], ctorParameters: () => [] });
|
|
@@ -5987,46 +6671,36 @@ class StreamStatusTelemetryService extends SubService {
|
|
|
5987
6671
|
VideoEncoderQP,
|
|
5988
6672
|
};
|
|
5989
6673
|
}
|
|
5990
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
5991
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
6674
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StreamStatusTelemetryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
6675
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StreamStatusTelemetryService, providedIn: 'root' }); }
|
|
5992
6676
|
}
|
|
5993
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
6677
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StreamStatusTelemetryService, decorators: [{
|
|
5994
6678
|
type: Injectable,
|
|
5995
6679
|
args: [{ providedIn: 'root' }]
|
|
5996
6680
|
}], ctorParameters: () => [] });
|
|
5997
6681
|
|
|
5998
6682
|
/**
|
|
5999
|
-
*
|
|
6683
|
+
* Telemetry for the WebRTC stream lifecycle.
|
|
6000
6684
|
*
|
|
6001
|
-
*
|
|
6002
|
-
*
|
|
6003
|
-
*
|
|
6004
|
-
*
|
|
6005
|
-
*
|
|
6006
|
-
*
|
|
6007
|
-
*
|
|
6008
|
-
*
|
|
6009
|
-
* - `stream.quality_degraded` — on QP entering `red` (>35)
|
|
6010
|
-
* - `stream.quality_recovered` — on QP leaving `red`
|
|
6011
|
-
* - `stream.fps_low` — when the window FPS p50 < 70% of the target
|
|
6012
|
-
* - `stream.session_ended` — once per session, on disconnect/pagehide/restart
|
|
6685
|
+
* The event taxonomy is deliberately small — phase-specific detail rides inside
|
|
6686
|
+
* `stream.phase_ended`'s payload rather than becoming its own event type:
|
|
6687
|
+
* `session_started`, `phase_ended` (once per closer in {@link phaseCatalog}),
|
|
6688
|
+
* `sample` (every 5s, window-aggregated), `quality_degraded` /
|
|
6689
|
+
* `quality_recovered` (QP entering/leaving `red`), `fps_low`, `session_ended`.
|
|
6690
|
+
* Every wire shape lives in `interfaces/stream-telemetry-events.interface.ts`,
|
|
6691
|
+
* and `track()` / `emitLifecycle()` are typed against it — a drifting payload is
|
|
6692
|
+
* a compile error.
|
|
6013
6693
|
*
|
|
6014
|
-
*
|
|
6015
|
-
*
|
|
6016
|
-
*
|
|
6017
|
-
*
|
|
6018
|
-
* answered, the first events are queued and flushed with it (see
|
|
6694
|
+
* `sessionId` IS the stream's connection id (`selectCirrusConnectionId`), the
|
|
6695
|
+
* value the debug overlay labels "Connection Id", so a telemetry session can be
|
|
6696
|
+
* matched to a Cirrus player session. That id only exists once orchestration
|
|
6697
|
+
* answered, so early events are queued and flushed with it (see
|
|
6019
6698
|
* {@link SessionState.wireId}); a session that never got one falls back to a
|
|
6020
|
-
*
|
|
6021
|
-
*
|
|
6022
|
-
* jumps.
|
|
6699
|
+
* local uuid. Samples carry a monotonic `seq` for server-side ordering and
|
|
6700
|
+
* dedup, and durations use `performance.now()` to survive wall-clock jumps.
|
|
6023
6701
|
*
|
|
6024
|
-
* NOTE:
|
|
6025
|
-
*
|
|
6026
|
-
*
|
|
6027
|
-
* Every wire shape lives in `interfaces/stream-telemetry-events.interface.ts`
|
|
6028
|
-
* — `track()` / `emitLifecycle()` are typed against it, so a payload that
|
|
6029
|
-
* drifts from the contract is a compile error.
|
|
6702
|
+
* NOTE: `stream.session_ended` only survives tab close if the Mixpanel client
|
|
6703
|
+
* is configured with `api_transport: 'sendBeacon'`.
|
|
6030
6704
|
*/
|
|
6031
6705
|
/** Trim a resource URL to its path: drop origin and query string so the
|
|
6032
6706
|
* emitted name is short, stable, and not a PII-bearing query. */
|
|
@@ -6351,45 +7025,31 @@ class StreamStatusTelemetryService2 {
|
|
|
6351
7025
|
}
|
|
6352
7026
|
}
|
|
6353
7027
|
init() {
|
|
6354
|
-
//
|
|
6355
|
-
//
|
|
6356
|
-
//
|
|
6357
|
-
//
|
|
6358
|
-
//
|
|
6359
|
-
//
|
|
6360
|
-
// per real attempt
|
|
6361
|
-
//
|
|
6362
|
-
// (prefetch adoption / fresh connect). So binding here yields one session
|
|
6363
|
-
// per attempt instead of a burst of `restart` churn sessions. Genuine
|
|
6364
|
-
// reconnects (e.g. DataChannelTimeout) re-enter the same path and
|
|
6365
|
-
// correctly end the prior session as `restart` + start a new one.
|
|
7028
|
+
// Bound to `setEstablishingConnection(true)`, not `initSignalling`, which
|
|
7029
|
+
// fires several times per page load (unreal-scene effect, `startStream`,
|
|
7030
|
+
// reconnect). `connectToSignaling$` collapses those into one attempt
|
|
7031
|
+
// (`exhaustMap` + `!cirrusConnected`), and its `startWith(...)` is the
|
|
7032
|
+
// single dispatch site for `true` — downstream of that guard and ahead of
|
|
7033
|
+
// both branches (prefetch adoption / fresh connect). So this yields one
|
|
7034
|
+
// session per real attempt instead of a burst of `restart` churn, while
|
|
7035
|
+
// genuine reconnects still end the prior session as `restart`.
|
|
6366
7036
|
//
|
|
6367
|
-
// Do NOT add a second dispatch site:
|
|
6368
|
-
// `
|
|
6369
|
-
//
|
|
7037
|
+
// Do NOT add a second dispatch site: every extra `true` becomes
|
|
7038
|
+
// `endSession('restart')` + a new session, discarding the first session's
|
|
7039
|
+
// page-load measurement and its prefetch adoption.
|
|
6370
7040
|
this.actions$
|
|
6371
7041
|
.pipe(ofType(setEstablishingConnection), filter$1(({ value }) => value === true), takeUntil$1(this.destroy$))
|
|
6372
7042
|
.subscribe(() => this.startSession());
|
|
6373
|
-
//
|
|
6374
|
-
//
|
|
6375
|
-
//
|
|
6376
|
-
//
|
|
6377
|
-
//
|
|
6378
|
-
//
|
|
6379
|
-
// `
|
|
6380
|
-
// synchronously inside that reducer's emission, before the
|
|
6381
|
-
// follow-up effect (`destroyUnrealScene → destroyRemoteConnections({Destroy})`)
|
|
6382
|
-
// gets a chance to write `Destroy` back into state — so the
|
|
6383
|
-
// subscriber would see `None` and end as `'disconnected'`.
|
|
6384
|
-
//
|
|
6385
|
-
// Subscribing to the actions instead lets us pick the right
|
|
6386
|
-
// reason per dispatched action, and `endSession` is idempotent
|
|
6387
|
-
// (`if (!this.session) return`) so any cascading second trigger
|
|
6388
|
-
// is a no-op. Coverage:
|
|
7043
|
+
// End triggers read the action stream, not the state, on purpose. The
|
|
7044
|
+
// `destroyUnrealScene` reducer resets the whole unreal state in one step,
|
|
7045
|
+
// so `cirrusConnected` flips to `false` while `disconnectReason` resets to
|
|
7046
|
+
// `None`. A state subscriber fires synchronously inside that emission —
|
|
7047
|
+
// before the follow-up effect writes `Destroy` back — and would report
|
|
7048
|
+
// `'disconnected'`. Per-action subscriptions pick the right reason instead,
|
|
7049
|
+
// and `endSession` is idempotent, so a cascading second trigger is a no-op:
|
|
6389
7050
|
// - `destroyUnrealScene` → `'destroy'` (route change, removed from DOM)
|
|
6390
|
-
// - `setCirrusDisconnected` → `'disconnected'` (WS close, AFK,
|
|
6391
|
-
//
|
|
6392
|
-
// read from current state in `endSession`)
|
|
7051
|
+
// - `setCirrusDisconnected` → `'disconnected'` (WS close, AFK, manual
|
|
7052
|
+
// drop, WebRTCError — granular cause read from state in `endSession`)
|
|
6393
7053
|
this.actions$
|
|
6394
7054
|
.pipe(ofType(destroyUnrealScene), takeUntil$1(this.destroy$))
|
|
6395
7055
|
.subscribe(() => this.endSession('destroy'));
|
|
@@ -6685,11 +7345,10 @@ class StreamStatusTelemetryService2 {
|
|
|
6685
7345
|
/**
|
|
6686
7346
|
* Emit the region / signaling / webrtc phases for an ADOPTED connection.
|
|
6687
7347
|
*
|
|
6688
|
-
* The prefetch script established the connection in
|
|
6689
|
-
* so
|
|
6690
|
-
*
|
|
6691
|
-
*
|
|
6692
|
-
* happened while the page was loading. Each phase ships:
|
|
7348
|
+
* The prefetch script established the connection in parallel with page load,
|
|
7349
|
+
* so phases sit at their real anchor-relative spans — shifted left to overlap
|
|
7350
|
+
* the HTML-loading / route-idle rows instead of following them. Each phase
|
|
7351
|
+
* ships:
|
|
6693
7352
|
* - `duration` — the real sub-step time the prefetch spent.
|
|
6694
7353
|
* - `spanStartMs` — anchor-relative start, so the viewer left-shifts the bar.
|
|
6695
7354
|
* - `adoptionAtMs` — where Angular took over (the next phase, Unreal
|
|
@@ -6955,22 +7614,15 @@ class StreamStatusTelemetryService2 {
|
|
|
6955
7614
|
}
|
|
6956
7615
|
}
|
|
6957
7616
|
/**
|
|
6958
|
-
*
|
|
6959
|
-
*
|
|
6960
|
-
*
|
|
7617
|
+
* Aggregates `performance.getEntriesByType('resource')` by `initiatorType`,
|
|
7618
|
+
* split at `window.load`: `resources` for entries before `loadEventEnd` (the
|
|
7619
|
+
* actual page weight) and `lazyResources` for those after it (typically the
|
|
7620
|
+
* route's lazy chunks and manifests, downloaded when the user navigates to the
|
|
7621
|
+
* sub-route the streamer lives on). If `loadEventEnd` is 0 or unknown,
|
|
7622
|
+
* everything lands in `resources` and `lazyResources` is null.
|
|
6961
7623
|
*
|
|
6962
|
-
*
|
|
6963
|
-
*
|
|
6964
|
-
* - `lazyResources` — fetched after `loadEventEnd` (= typically the
|
|
6965
|
-
* route's lazy-loaded chunks, JSON manifests etc. that download
|
|
6966
|
-
* when the user navigates to a sub-route the streamer lives on).
|
|
6967
|
-
*
|
|
6968
|
-
* When `loadEventEnd` is 0/unknown, everything goes into `resources`
|
|
6969
|
-
* and `lazyResources` is null — old behavior.
|
|
6970
|
-
*
|
|
6971
|
-
* `transferSize === 0 && decodedBodySize > 0` means the resource came from
|
|
6972
|
-
* the HTTP cache — counted separately so cached hits don't inflate
|
|
6973
|
-
* the "bytes on the wire" metric.
|
|
7624
|
+
* `transferSize === 0 && decodedBodySize > 0` means an HTTP-cache hit, counted
|
|
7625
|
+
* separately so it does not inflate the bytes-on-the-wire metric.
|
|
6974
7626
|
*/
|
|
6975
7627
|
collectResourceTotals(loadEventEnd) {
|
|
6976
7628
|
try {
|
|
@@ -7092,10 +7744,10 @@ class StreamStatusTelemetryService2 {
|
|
|
7092
7744
|
emit(event, data) {
|
|
7093
7745
|
this.store.dispatch(trackTelemetryData({ event, data }));
|
|
7094
7746
|
}
|
|
7095
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7096
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
7747
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StreamStatusTelemetryService2, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
7748
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StreamStatusTelemetryService2, providedIn: 'root' }); }
|
|
7097
7749
|
}
|
|
7098
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
7750
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StreamStatusTelemetryService2, decorators: [{
|
|
7099
7751
|
type: Injectable,
|
|
7100
7752
|
args: [{ providedIn: 'root' }]
|
|
7101
7753
|
}], ctorParameters: () => [] });
|
|
@@ -7181,10 +7833,10 @@ class FileHandlerService {
|
|
|
7181
7833
|
return observable;
|
|
7182
7834
|
});
|
|
7183
7835
|
}
|
|
7184
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7185
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
7836
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FileHandlerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
7837
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FileHandlerService, providedIn: 'root' }); }
|
|
7186
7838
|
}
|
|
7187
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
7839
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FileHandlerService, decorators: [{
|
|
7188
7840
|
type: Injectable,
|
|
7189
7841
|
args: [{ providedIn: 'root' }]
|
|
7190
7842
|
}] });
|
|
@@ -7273,86 +7925,31 @@ class AnalyticsService extends SubService {
|
|
|
7273
7925
|
Logger.log('Analytics Event:', name, params);
|
|
7274
7926
|
this.store.dispatch(saveAnalyticsEvent({ event: { name, params } }));
|
|
7275
7927
|
}
|
|
7276
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7277
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
7928
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AnalyticsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
7929
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AnalyticsService, providedIn: 'root' }); }
|
|
7278
7930
|
}
|
|
7279
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
7931
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AnalyticsService, decorators: [{
|
|
7280
7932
|
type: Injectable,
|
|
7281
7933
|
args: [{ providedIn: 'root' }]
|
|
7282
7934
|
}], ctorParameters: () => [] });
|
|
7283
7935
|
|
|
7284
7936
|
/**
|
|
7285
|
-
* Adaptive FPS controller
|
|
7286
|
-
*
|
|
7287
|
-
*
|
|
7288
|
-
* ## How it works
|
|
7289
|
-
*
|
|
7290
|
-
* The service subscribes to `VideoService.videoStats$` (emitted every 250 ms)
|
|
7291
|
-
* and collects samples of FPS, bitrate, and QP (Quantization Parameter).
|
|
7292
|
-
* Every {@link SAMPLE_WINDOW} ticks (~2 s) it averages the collected samples
|
|
7293
|
-
* and feeds them into a set of **fuzzy-logic membership functions** that
|
|
7294
|
-
* classify each metric into overlapping quality bands.
|
|
7295
|
-
*
|
|
7296
|
-
* ### Input signals
|
|
7297
|
-
*
|
|
7298
|
-
* **1. FPS ratio** = `actualFPS / currentTargetFPS` (0..1+)
|
|
7299
|
-
*
|
|
7300
|
-
* | Band | Range | Meaning |
|
|
7301
|
-
* |--------|---------------------|-----------------------------------------------|
|
|
7302
|
-
* | low | ratio < 0.7 → 1.0, linear ramp 0.7..0.9 → 0 | Stream cannot keep up with the target |
|
|
7303
|
-
* | okays | triangle 0.8..1.0, peak at 0.95 | Stream roughly matches the target |
|
|
7304
|
-
* | high | ratio 0.9..1.0 → ramp, >1.0 → 1.0 | Stream meets or exceeds the target |
|
|
7937
|
+
* Adaptive FPS controller: watches the incoming WebRTC stream and steers Unreal's
|
|
7938
|
+
* `t.MaxFPS` between the discrete {@link FPS_STEPS}.
|
|
7305
7939
|
*
|
|
7306
|
-
*
|
|
7940
|
+
* Every {@link SAMPLE_WINDOW} ticks of `VideoService.videoStats$` (250 ms each)
|
|
7941
|
+
* it averages FPS, bitrate and QP, runs them through the fuzzy membership
|
|
7942
|
+
* functions below, and picks a decision by first-match rules. Fuzzy bands rather
|
|
7943
|
+
* than hard thresholds so a metric sitting on a boundary does not oscillate.
|
|
7307
7944
|
*
|
|
7308
|
-
*
|
|
7945
|
+
* Cooldowns between steps are deliberately asymmetric: stepping *down* again is
|
|
7946
|
+
* allowed after {@link COOLDOWN_DECREASE_AFTER_DECREASE_MS}, but stepping back
|
|
7947
|
+
* *up* after a decrease waits {@link COOLDOWN_INCREASE_AFTER_DECREASE_MS} — a
|
|
7948
|
+
* stream that just failed its target is likely to fail it again.
|
|
7309
7949
|
*
|
|
7310
|
-
*
|
|
7311
|
-
*
|
|
7312
|
-
*
|
|
7313
|
-
* | not high | load < 0.5 → 0.0 | Bandwidth headroom is available |
|
|
7314
|
-
*
|
|
7315
|
-
* **3. Quality** — mapped from QP via `mapQpToQuality()` (see {@link Quality}):
|
|
7316
|
-
*
|
|
7317
|
-
* | Quality | QP range | Meaning |
|
|
7318
|
-
* |----------|-----------|-------------------------------------------------|
|
|
7319
|
-
* | `lime` | QP <= 26 | Good — encoder has enough headroom |
|
|
7320
|
-
* | `orange` | QP 27..35 | Fair — encoder is under moderate pressure |
|
|
7321
|
-
* | `red` | QP > 35 | Poor — heavy compression, visible artifacts |
|
|
7322
|
-
*
|
|
7323
|
-
* ### Decision rules (evaluated in priority order, first match wins)
|
|
7324
|
-
*
|
|
7325
|
-
* | # | Condition | Decision |
|
|
7326
|
-
* |---|------------------------------------------------------------|--------------|
|
|
7327
|
-
* | 1 | FPS ratio is **low** (membership > 0.5) | **decrease** |
|
|
7328
|
-
* | 2 | FPS ratio is **ok** AND quality is `red` | **decrease** |
|
|
7329
|
-
* | 3 | FPS ratio is **ok** AND bitrate **high** AND quality is `orange` | **hold** |
|
|
7330
|
-
* | 4 | FPS ratio is **high** AND quality is `lime` AND bitrate **not high** | **increase** |
|
|
7331
|
-
* | — | Everything else | **hold** |
|
|
7332
|
-
*
|
|
7333
|
-
* ## Cooldown-based throttling
|
|
7334
|
-
*
|
|
7335
|
-
* The service continuously evaluates fuzzy rules in every sample window.
|
|
7336
|
-
* After each FPS step change it enforces a cooldown before the next
|
|
7337
|
-
* change can be applied. The cooldown duration depends on the
|
|
7338
|
-
* (previous decision → next decision) pair:
|
|
7339
|
-
*
|
|
7340
|
-
* | Previous | Next | Cooldown |
|
|
7341
|
-
* |-----------|-----------|-----------------------------------------------------|
|
|
7342
|
-
* | decrease | decrease | {@link COOLDOWN_DECREASE_AFTER_DECREASE_MS} (2 s) |
|
|
7343
|
-
* | decrease | increase | {@link COOLDOWN_INCREASE_AFTER_DECREASE_MS} (10 s) |
|
|
7344
|
-
* | increase | decrease | {@link COOLDOWN_AFTER_INCREASE_MS} (2 s) |
|
|
7345
|
-
* | increase | increase | {@link COOLDOWN_AFTER_INCREASE_MS} (2 s) |
|
|
7346
|
-
*
|
|
7347
|
-
* This means the system reacts quickly after an increase (2 s in any
|
|
7348
|
-
* direction) but is cautious about stepping back up after a decrease
|
|
7349
|
-
* (10 s), while still allowing consecutive decreases at 2 s intervals.
|
|
7350
|
-
*
|
|
7351
|
-
* ## FPS dispatch
|
|
7352
|
-
*
|
|
7353
|
-
* FPS changes are dispatched via the NgRx `setMaxFps` action, which triggers
|
|
7354
|
-
* the existing `UnrealEffects.setMaxFps$` effect that sends the
|
|
7355
|
-
* `t.MaxFPS <value>` console command to Unreal Engine.
|
|
7950
|
+
* Changes go out as the `setMaxFps` action, not a direct command: the existing
|
|
7951
|
+
* `UnrealEffects.setMaxFps$` effect turns it into the `t.MaxFPS <value>` console
|
|
7952
|
+
* command.
|
|
7356
7953
|
*/
|
|
7357
7954
|
class FpsMonitorService extends SubService {
|
|
7358
7955
|
constructor() {
|
|
@@ -7453,15 +8050,7 @@ class FpsMonitorService extends SubService {
|
|
|
7453
8050
|
const decision = this.evaluateDecision(avg, currentTarget);
|
|
7454
8051
|
this.upgradeFps(decision, avg.qp);
|
|
7455
8052
|
}
|
|
7456
|
-
/**
|
|
7457
|
-
* Combines fuzzy membership values into a single discrete decision.
|
|
7458
|
-
* Rules are evaluated in priority order — first match wins.
|
|
7459
|
-
*
|
|
7460
|
-
* Inputs:
|
|
7461
|
-
* - `fpsRatio` = avgFPS / currentTargetFPS (e.g., 45/60 = 0.75)
|
|
7462
|
-
* - `bitrateLoad` = avgBitrate / 20 Mbit/s (e.g., 12M/20M = 0.6)
|
|
7463
|
-
* - `quality` = mapQpToQuality(avgQP) → 'lime' | 'orange' | 'red'
|
|
7464
|
-
*/
|
|
8053
|
+
/** Rules are evaluated in priority order — first match wins. */
|
|
7465
8054
|
evaluateDecision(avg, currentTarget) {
|
|
7466
8055
|
const referenceTarget = currentTarget > 0 ? currentTarget : this.UNLIMITED_REFERENCE_FPS;
|
|
7467
8056
|
const fpsRatio = avg.fps / referenceTarget;
|
|
@@ -7501,21 +8090,10 @@ class FpsMonitorService extends SubService {
|
|
|
7501
8090
|
}
|
|
7502
8091
|
return 'hold';
|
|
7503
8092
|
}
|
|
7504
|
-
//
|
|
7505
|
-
//
|
|
7506
|
-
//
|
|
7507
|
-
|
|
7508
|
-
// Overlapping trapezoid/triangle shapes let multiple categories be partially
|
|
7509
|
-
// active at the same time, which makes the rules less brittle than hard thresholds.
|
|
7510
|
-
// ---------------------------------------------------------------------------
|
|
7511
|
-
/**
|
|
7512
|
-
* FPS ratio membership "low".
|
|
7513
|
-
* Input: a ratio = actualFPS / targetFPS (e.g., 42/60 = 0.70).
|
|
7514
|
-
*
|
|
7515
|
-
* ratio < 0.7 → 1.0 (clearly failing, e.g., 40/60)
|
|
7516
|
-
* ratio 0.7..0.9 → linear ramp down (e.g., 0.8 → 0.5)
|
|
7517
|
-
* a ratio > 0.9 → 0.0 (keeping up)
|
|
7518
|
-
*/
|
|
8093
|
+
// Fuzzy membership functions: normalised input (0..1+) → membership degree
|
|
8094
|
+
// (0..1). The shapes overlap on purpose, so several bands can be partially
|
|
8095
|
+
// active at once and the rules stay less brittle than hard thresholds.
|
|
8096
|
+
/** "low" — the stream cannot keep up with its target. */
|
|
7519
8097
|
membershipFpsLow(ratio) {
|
|
7520
8098
|
if (ratio < 0.7)
|
|
7521
8099
|
return 1.0;
|
|
@@ -7523,15 +8101,7 @@ class FpsMonitorService extends SubService {
|
|
|
7523
8101
|
return 0.0;
|
|
7524
8102
|
return (0.9 - ratio) / 0.2;
|
|
7525
8103
|
}
|
|
7526
|
-
/**
|
|
7527
|
-
* FPS ratio membership "ok" — triangle shape.
|
|
7528
|
-
* Input: ratio = actualFPS / targetFPS.
|
|
7529
|
-
*
|
|
7530
|
-
* ratio < 0.8 → 0.0
|
|
7531
|
-
* ratio 0.8..0.95 → ramp up, peak at 0.95 (e.g., 57/60)
|
|
7532
|
-
* ratio 0.95..1.0 → ramp down
|
|
7533
|
-
* a ratio > 1.0 → 0.0
|
|
7534
|
-
*/
|
|
8104
|
+
/** "ok" — triangle peaking just under the target. */
|
|
7535
8105
|
membershipFpsOk(ratio) {
|
|
7536
8106
|
if (ratio < 0.8)
|
|
7537
8107
|
return 0.0;
|
|
@@ -7541,14 +8111,7 @@ class FpsMonitorService extends SubService {
|
|
|
7541
8111
|
return (1.0 - ratio) / 0.05;
|
|
7542
8112
|
return 0.0;
|
|
7543
8113
|
}
|
|
7544
|
-
/**
|
|
7545
|
-
* FPS ratio membership "high".
|
|
7546
|
-
* Input: ratio = actualFPS / targetFPS.
|
|
7547
|
-
*
|
|
7548
|
-
* ratio < 0.9 → 0.0
|
|
7549
|
-
* ratio 0.9..1.0 → linear ramp up (e.g., 0.95 → 0.5)
|
|
7550
|
-
* a ratio >= 1.0 → 1.0 (meeting or exceeding target, e.g., 60/60)
|
|
7551
|
-
*/
|
|
8114
|
+
/** "high" — the stream meets or exceeds its target. */
|
|
7552
8115
|
membershipFpsHigh(ratio) {
|
|
7553
8116
|
if (ratio < 0.9)
|
|
7554
8117
|
return 0.0;
|
|
@@ -7556,14 +8119,7 @@ class FpsMonitorService extends SubService {
|
|
|
7556
8119
|
return 1.0;
|
|
7557
8120
|
return (ratio - 0.9) / 0.1;
|
|
7558
8121
|
}
|
|
7559
|
-
/**
|
|
7560
|
-
* Bitrate load membership "high".
|
|
7561
|
-
* Input: a load = currentBitrate / MAX_BITRATE (20 Mbit/s).
|
|
7562
|
-
*
|
|
7563
|
-
* load < 0.5 → 0.0 (below 10 Mbit/s — plenty of headroom)
|
|
7564
|
-
* load 0.5..0.8 → linear ramp (e.g., 13M/20M = 0.65 → 0.5)
|
|
7565
|
-
* load > 0.8 → 1.0 (above 16 Mbit/s — near capacity)
|
|
7566
|
-
*/
|
|
8122
|
+
/** "high" — the encoder is using most of the available bandwidth. */
|
|
7567
8123
|
membershipBitrateHigh(load) {
|
|
7568
8124
|
if (load < 0.5)
|
|
7569
8125
|
return 0.0;
|
|
@@ -7643,10 +8199,10 @@ class FpsMonitorService extends SubService {
|
|
|
7643
8199
|
}
|
|
7644
8200
|
return { fps: fps / len, bitrate: bitrate / len, qp: qp / len };
|
|
7645
8201
|
}
|
|
7646
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7647
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.
|
|
8202
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FpsMonitorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
8203
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FpsMonitorService, providedIn: 'root' }); }
|
|
7648
8204
|
}
|
|
7649
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8205
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FpsMonitorService, decorators: [{
|
|
7650
8206
|
type: Injectable,
|
|
7651
8207
|
args: [{ providedIn: 'root' }]
|
|
7652
8208
|
}], ctorParameters: () => [] });
|
|
@@ -7681,10 +8237,10 @@ class AfkTimeoutModalComponent {
|
|
|
7681
8237
|
resetAfk() {
|
|
7682
8238
|
this.#afkService.reset();
|
|
7683
8239
|
}
|
|
7684
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7685
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
8240
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AfkTimeoutModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8241
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: AfkTimeoutModalComponent, isStandalone: true, selector: "app-afk-timeout-modal", inputs: { uiClasses: { classPropertyName: "uiClasses", publicName: "uiClasses", isSignal: true, isRequired: false, transformFunction: null }, contentTemplate: { classPropertyName: "contentTemplate", publicName: "contentTemplate", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isShowAfkPopup()) {\n <div\n (click)=\"resetAfk()\"\n [class]=\"scrimSkin()\"\n class=\"afk-anchor clickableState\"\n id=\"videoPlayOverlay\"\n >\n <div [class]=\"cardSkin()\">\n @if (contentTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: slotContext }\"\n />\n } @else {\n <div aria-hidden=\"true\" class=\"resume-box__pic\" role=\"presentation\">\n <div [innerHTML]=\"afkCountdown()\" class=\"text-number\"></div>\n </div>\n <div class=\"resume-box__text\">\n <h3 class=\"resume-box__heading\">Session will time out soon</h3>\n <p>\n No activity detected. Press 'Continue' if you wish to keep your\n session active\n </p>\n </div>\n <app-unreal-button\n [fullWidth]=\"true\"\n [data-testid]=\"'continue-session'\"\n [class]=\"buttonSkin()\"\n weight=\"primary\"\n size=\"lg\"\n >\n Continue\n </app-unreal-button>\n }\n </div>\n </div>\n}\n", styles: [".afk-anchor{position:absolute;z-index:30;top:0;width:100%;height:100%}.afk-scrim{font-size:1.8em;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));background-color:var(--unreal-surface-scrim, rgba(100, 100, 100, .7))}.clickableState{display:flex;justify-content:center;align-items:center;cursor:pointer}.textDisplayState{display:flex}.hiddenState{display:none}.resume-box{width:340px;padding:32px 20px 20px;flex-direction:column;align-items:center;border-radius:var(--unreal-radius-card, var(--src-border-rounded-parent, 8px));background:var(--unreal-surface-card, var(--src-surface-container-main, #fff));box-shadow:var(--unreal-shadow-card, 0 26px 80px 0 rgba(0, 0, 0, .2), 0 0 1px 0 rgba(0, 0, 0, .2))}.resume-box__pic{width:72px;height:72px;margin:0 auto 22px;border-radius:48px;background:#ecf0f2;padding:12px;display:flex;align-items:center;justify-content:center}.text-number{color:var(--unreal-text-main, #1f2937);text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:30px;font-style:normal;font-weight:400;line-height:24px}.resume-box__text{margin-bottom:18px}.resume-box__text p{text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:24px;color:var(--unreal-text-secondary, var(--src-text-body-secondary, #6b7280))}.resume-box__text .resume-box__heading{color:var(--unreal-text-main, var(--src-text-body-main, #1f2937));text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:18px;font-style:normal;font-weight:500;line-height:26px;margin-bottom:8px}\n"], dependencies: [{ kind: "component", type: UnrealButtonComponent, selector: "app-unreal-button", inputs: ["type", "weight", "size", "fullWidth", "isDisabled", "data-testid", "ariaLabel"], outputs: ["clicked"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7686
8242
|
}
|
|
7687
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8243
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AfkTimeoutModalComponent, decorators: [{
|
|
7688
8244
|
type: Component,
|
|
7689
8245
|
args: [{ selector: 'app-afk-timeout-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent, NgTemplateOutlet], template: "@if (isShowAfkPopup()) {\n <div\n (click)=\"resetAfk()\"\n [class]=\"scrimSkin()\"\n class=\"afk-anchor clickableState\"\n id=\"videoPlayOverlay\"\n >\n <div [class]=\"cardSkin()\">\n @if (contentTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: slotContext }\"\n />\n } @else {\n <div aria-hidden=\"true\" class=\"resume-box__pic\" role=\"presentation\">\n <div [innerHTML]=\"afkCountdown()\" class=\"text-number\"></div>\n </div>\n <div class=\"resume-box__text\">\n <h3 class=\"resume-box__heading\">Session will time out soon</h3>\n <p>\n No activity detected. Press 'Continue' if you wish to keep your\n session active\n </p>\n </div>\n <app-unreal-button\n [fullWidth]=\"true\"\n [data-testid]=\"'continue-session'\"\n [class]=\"buttonSkin()\"\n weight=\"primary\"\n size=\"lg\"\n >\n Continue\n </app-unreal-button>\n }\n </div>\n </div>\n}\n", styles: [".afk-anchor{position:absolute;z-index:30;top:0;width:100%;height:100%}.afk-scrim{font-size:1.8em;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));background-color:var(--unreal-surface-scrim, rgba(100, 100, 100, .7))}.clickableState{display:flex;justify-content:center;align-items:center;cursor:pointer}.textDisplayState{display:flex}.hiddenState{display:none}.resume-box{width:340px;padding:32px 20px 20px;flex-direction:column;align-items:center;border-radius:var(--unreal-radius-card, var(--src-border-rounded-parent, 8px));background:var(--unreal-surface-card, var(--src-surface-container-main, #fff));box-shadow:var(--unreal-shadow-card, 0 26px 80px 0 rgba(0, 0, 0, .2), 0 0 1px 0 rgba(0, 0, 0, .2))}.resume-box__pic{width:72px;height:72px;margin:0 auto 22px;border-radius:48px;background:#ecf0f2;padding:12px;display:flex;align-items:center;justify-content:center}.text-number{color:var(--unreal-text-main, #1f2937);text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:30px;font-style:normal;font-weight:400;line-height:24px}.resume-box__text{margin-bottom:18px}.resume-box__text p{text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:24px;color:var(--unreal-text-secondary, var(--src-text-body-secondary, #6b7280))}.resume-box__text .resume-box__heading{color:var(--unreal-text-main, var(--src-text-body-main, #1f2937));text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:18px;font-style:normal;font-weight:500;line-height:26px;margin-bottom:8px}\n"] }]
|
|
7690
8246
|
}], propDecorators: { uiClasses: [{ type: i0.Input, args: [{ isSignal: true, alias: "uiClasses", required: false }] }], contentTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentTemplate", required: false }] }] } });
|
|
@@ -7696,10 +8252,10 @@ class FreezeFrameComponent {
|
|
|
7696
8252
|
this.combinedFreeze = this.#store.selectSignal(selectFreezeFrameCombinedDataUrl);
|
|
7697
8253
|
}
|
|
7698
8254
|
#store;
|
|
7699
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7700
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
8255
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FreezeFrameComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8256
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: FreezeFrameComponent, isStandalone: true, selector: "app-freeze-frame", ngImport: i0, template: "@let image = combinedFreeze();\n@let progress = freezeFrameProgressMessageFromVideo();\n\n<div class=\"freeze-images\">\n @if (image) {\n <img [src]=\"image\" class=\"videoStillImage\" alt=\"freezeFrameImage\" />\n }\n\n @if (progress) {\n <div class=\"progress-status\">\n {{ progress }}\n </div>\n }\n</div>\n", styles: [".freeze-images{pointer-events:none;position:absolute;left:0;top:0;width:100%;height:100%;z-index:1}.freeze-images .freezeFrameOverlay{top:0;left:0;width:100%;height:100%;position:absolute;object-fit:cover;object-position:center}.freeze-images .videoStillImage{position:absolute;z-index:1;top:0;left:0;width:100%;height:100%;object-fit:cover}.freeze-images .progress-status{position:absolute;top:50%;left:50%;z-index:1;display:flex;flex-direction:column;justify-content:center;align-items:center;width:auto;height:auto;margin:0;padding:10px;background-color:#ffffffb3;border:1px solid grey;transform:translate(-50%,-50%)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7701
8257
|
}
|
|
7702
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8258
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FreezeFrameComponent, decorators: [{
|
|
7703
8259
|
type: Component,
|
|
7704
8260
|
args: [{ selector: 'app-freeze-frame', changeDetection: ChangeDetectionStrategy.OnPush, template: "@let image = combinedFreeze();\n@let progress = freezeFrameProgressMessageFromVideo();\n\n<div class=\"freeze-images\">\n @if (image) {\n <img [src]=\"image\" class=\"videoStillImage\" alt=\"freezeFrameImage\" />\n }\n\n @if (progress) {\n <div class=\"progress-status\">\n {{ progress }}\n </div>\n }\n</div>\n", styles: [".freeze-images{pointer-events:none;position:absolute;left:0;top:0;width:100%;height:100%;z-index:1}.freeze-images .freezeFrameOverlay{top:0;left:0;width:100%;height:100%;position:absolute;object-fit:cover;object-position:center}.freeze-images .videoStillImage{position:absolute;z-index:1;top:0;left:0;width:100%;height:100%;object-fit:cover}.freeze-images .progress-status{position:absolute;top:50%;left:50%;z-index:1;display:flex;flex-direction:column;justify-content:center;align-items:center;width:auto;height:auto;margin:0;padding:10px;background-color:#ffffffb3;border:1px solid grey;transform:translate(-50%,-50%)}\n"] }]
|
|
7705
8261
|
}] });
|
|
@@ -7714,10 +8270,10 @@ class ImageLoadingSrcComponent {
|
|
|
7714
8270
|
loadingImageError() {
|
|
7715
8271
|
this.#store.dispatch(setLoadingImageSrc({ src: '' }));
|
|
7716
8272
|
}
|
|
7717
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7718
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
8273
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ImageLoadingSrcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8274
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: ImageLoadingSrcComponent, isStandalone: true, selector: "app-image-loading-src", ngImport: i0, template: "@let image = imageLoadingSrc();\n@if (isLoaderScreenVisible()) {\n <div class=\"preload\">\n <div class=\"back\">\n @if (image) {\n <img\n (error)=\"loadingImageError()\"\n [ngSrc]=\"image\"\n fill\n loading=\"lazy\"\n alt=\"image loading src\"\n />\n }\n </div>\n </div>\n}\n", styles: [".preload{position:absolute;top:0;left:0;width:100%;height:100%;text-align:center}.preload .back{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%}.preload .back img{width:100%;height:100%;object-fit:cover}.preload .back{background-color:var(--unreal-surface-screen, #fff)}\n"], dependencies: [{ kind: "directive", type: NgOptimizedImage, selector: "img[ngSrc]", inputs: ["ngSrc", "ngSrcset", "sizes", "width", "height", "decoding", "loading", "priority", "loaderParams", "disableOptimizedSrcset", "fill", "placeholder", "placeholderConfig", "src", "srcset"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7719
8275
|
}
|
|
7720
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8276
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ImageLoadingSrcComponent, decorators: [{
|
|
7721
8277
|
type: Component,
|
|
7722
8278
|
args: [{ selector: 'app-image-loading-src', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgOptimizedImage], template: "@let image = imageLoadingSrc();\n@if (isLoaderScreenVisible()) {\n <div class=\"preload\">\n <div class=\"back\">\n @if (image) {\n <img\n (error)=\"loadingImageError()\"\n [ngSrc]=\"image\"\n fill\n loading=\"lazy\"\n alt=\"image loading src\"\n />\n }\n </div>\n </div>\n}\n", styles: [".preload{position:absolute;top:0;left:0;width:100%;height:100%;text-align:center}.preload .back{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%}.preload .back img{width:100%;height:100%;object-fit:cover}.preload .back{background-color:var(--unreal-surface-screen, #fff)}\n"] }]
|
|
7723
8279
|
}] });
|
|
@@ -7800,10 +8356,10 @@ class StatGraphComponent {
|
|
|
7800
8356
|
}
|
|
7801
8357
|
this.draw();
|
|
7802
8358
|
}
|
|
7803
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7804
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.
|
|
8359
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StatGraphComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8360
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.3", type: StatGraphComponent, isStandalone: true, selector: "app-stat-graph", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, stat: { classPropertyName: "stat", publicName: "stat", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, tickStep: { classPropertyName: "tickStep", publicName: "tickStep", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "window:resize": "resize()" } }, viewQueries: [{ propertyName: "graph", first: true, predicate: ["graph"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"content\">\n <p>{{ label() }}: {{ current() }} | Min:{{ min() }} | Max:{{ max() }}</p>\n <canvas #graph class=\"graph\"></canvas>\n</div>\n", styles: [".content{width:100%;height:100%}.content p{color:#fff;margin:5px 0 0;height:25px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7805
8361
|
}
|
|
7806
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8362
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StatGraphComponent, decorators: [{
|
|
7807
8363
|
type: Component,
|
|
7808
8364
|
args: [{ selector: 'app-stat-graph', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"content\">\n <p>{{ label() }}: {{ current() }} | Min:{{ min() }} | Max:{{ max() }}</p>\n <canvas #graph class=\"graph\"></canvas>\n</div>\n", styles: [".content{width:100%;height:100%}.content p{color:#fff;margin:5px 0 0;height:25px}\n"] }]
|
|
7809
8365
|
}], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], stat: [{ type: i0.Input, args: [{ isSignal: true, alias: "stat", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], tickStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "tickStep", required: false }] }], graph: [{ type: i0.ViewChild, args: ['graph', { isSignal: true }] }], resize: [{
|
|
@@ -7818,10 +8374,10 @@ class UnrealResumeSlotDirective {
|
|
|
7818
8374
|
static ngTemplateContextGuard(_dir, _ctx) {
|
|
7819
8375
|
return true;
|
|
7820
8376
|
}
|
|
7821
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7822
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.
|
|
8377
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealResumeSlotDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
8378
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: UnrealResumeSlotDirective, isStandalone: true, selector: "ng-template[unrealResumeSlot]", ngImport: i0 }); }
|
|
7823
8379
|
}
|
|
7824
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8380
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealResumeSlotDirective, decorators: [{
|
|
7825
8381
|
type: Directive,
|
|
7826
8382
|
args: [{ selector: 'ng-template[unrealResumeSlot]' }]
|
|
7827
8383
|
}] });
|
|
@@ -7832,10 +8388,10 @@ class UnrealAfkSlotDirective {
|
|
|
7832
8388
|
static ngTemplateContextGuard(_dir, _ctx) {
|
|
7833
8389
|
return true;
|
|
7834
8390
|
}
|
|
7835
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7836
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.
|
|
8391
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealAfkSlotDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
8392
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: UnrealAfkSlotDirective, isStandalone: true, selector: "ng-template[unrealAfkSlot]", ngImport: i0 }); }
|
|
7837
8393
|
}
|
|
7838
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8394
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealAfkSlotDirective, decorators: [{
|
|
7839
8395
|
type: Directive,
|
|
7840
8396
|
args: [{ selector: 'ng-template[unrealAfkSlot]' }]
|
|
7841
8397
|
}] });
|
|
@@ -7846,10 +8402,10 @@ class UnrealStatusSlotDirective {
|
|
|
7846
8402
|
static ngTemplateContextGuard(_dir, _ctx) {
|
|
7847
8403
|
return true;
|
|
7848
8404
|
}
|
|
7849
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7850
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.
|
|
8405
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealStatusSlotDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
8406
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: UnrealStatusSlotDirective, isStandalone: true, selector: "ng-template[unrealStatusSlot]", ngImport: i0 }); }
|
|
7851
8407
|
}
|
|
7852
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8408
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealStatusSlotDirective, decorators: [{
|
|
7853
8409
|
type: Directive,
|
|
7854
8410
|
args: [{ selector: 'ng-template[unrealStatusSlot]' }]
|
|
7855
8411
|
}] });
|
|
@@ -7872,10 +8428,10 @@ class UnrealSpinnerComponent {
|
|
|
7872
8428
|
this.viewBox = computed(() => `0 0 ${this.size()} ${this.size()}`, /* @ts-ignore */
|
|
7873
8429
|
...(ngDevMode ? [{ debugName: "viewBox" }] : /* istanbul ignore next */ []));
|
|
7874
8430
|
}
|
|
7875
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7876
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.
|
|
8431
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealSpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8432
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.3", type: UnrealSpinnerComponent, isStandalone: true, selector: "app-unreal-spinner", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null }, strokeColor: { classPropertyName: "strokeColor", publicName: "strokeColor", isSignal: true, isRequired: false, transformFunction: null }, testID: { classPropertyName: "testID", publicName: "data-testid", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\n [attr.data-testid]=\"testID() || null\"\n [attr.aria-label]=\"ariaLabel()\"\n class=\"unreal-spinner-container\"\n role=\"status\"\n>\n <svg\n [attr.width]=\"size()\"\n [attr.height]=\"size()\"\n [attr.viewBox]=\"viewBox()\"\n [style.--unrealSpinnerSize]=\"size()\"\n class=\"unreal-spinner unreal-spinner--animation\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style=\"transform: rotate(-90deg)\"\n aria-hidden=\"true\"\n >\n <circle\n [attr.r]=\"radius()\"\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.stroke]=\"strokeColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"transparent\"\n stroke-linecap=\"round\"\n ></circle>\n </svg>\n</div>\n", styles: [":host{display:block}.unreal-spinner-container{position:relative;display:flex;justify-content:center;align-items:center;width:100%;height:100%}.unreal-spinner{position:relative;display:inline-block}.unreal-spinner--animation{animation:1.4s linear 0s infinite normal none running unrealSpinnerRotate}.unreal-spinner--animation circle{transform-origin:50% 50%;stroke-dasharray:calc(var(--unrealSpinnerSize) * 2 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:0;animation:1.6s ease-in-out 0s infinite normal none running unrealSpinnerDash}@keyframes unrealSpinnerRotate{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes unrealSpinnerDash{0%{stroke-dasharray:1px,calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:0}50%{stroke-dasharray:calc(var(--unrealSpinnerSize) * 2.5 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:calc(var(--unrealSpinnerSize) * .4 * -1px)}to{stroke-dasharray:calc(var(--unrealSpinnerSize) * 2.5 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:calc(var(--unrealSpinnerSize) * 3 * -1px)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7877
8433
|
}
|
|
7878
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8434
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealSpinnerComponent, decorators: [{
|
|
7879
8435
|
type: Component,
|
|
7880
8436
|
args: [{ selector: 'app-unreal-spinner', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n [attr.data-testid]=\"testID() || null\"\n [attr.aria-label]=\"ariaLabel()\"\n class=\"unreal-spinner-container\"\n role=\"status\"\n>\n <svg\n [attr.width]=\"size()\"\n [attr.height]=\"size()\"\n [attr.viewBox]=\"viewBox()\"\n [style.--unrealSpinnerSize]=\"size()\"\n class=\"unreal-spinner unreal-spinner--animation\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style=\"transform: rotate(-90deg)\"\n aria-hidden=\"true\"\n >\n <circle\n [attr.r]=\"radius()\"\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.stroke]=\"strokeColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"transparent\"\n stroke-linecap=\"round\"\n ></circle>\n </svg>\n</div>\n", styles: [":host{display:block}.unreal-spinner-container{position:relative;display:flex;justify-content:center;align-items:center;width:100%;height:100%}.unreal-spinner{position:relative;display:inline-block}.unreal-spinner--animation{animation:1.4s linear 0s infinite normal none running unrealSpinnerRotate}.unreal-spinner--animation circle{transform-origin:50% 50%;stroke-dasharray:calc(var(--unrealSpinnerSize) * 2 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:0;animation:1.6s ease-in-out 0s infinite normal none running unrealSpinnerDash}@keyframes unrealSpinnerRotate{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes unrealSpinnerDash{0%{stroke-dasharray:1px,calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:0}50%{stroke-dasharray:calc(var(--unrealSpinnerSize) * 2.5 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:calc(var(--unrealSpinnerSize) * .4 * -1px)}to{stroke-dasharray:calc(var(--unrealSpinnerSize) * 2.5 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:calc(var(--unrealSpinnerSize) * 3 * -1px)}}\n"] }]
|
|
7881
8437
|
}], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], strokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeWidth", required: false }] }], strokeColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeColor", required: false }] }], testID: [{ type: i0.Input, args: [{ isSignal: true, alias: "data-testid", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
|
|
@@ -7906,10 +8462,10 @@ class UnrealStatusComponent {
|
|
|
7906
8462
|
}
|
|
7907
8463
|
#store;
|
|
7908
8464
|
#loadingProgress;
|
|
7909
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7910
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
8465
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealStatusComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8466
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: UnrealStatusComponent, isStandalone: true, selector: "app-unreal-status", inputs: { uiClasses: { classPropertyName: "uiClasses", publicName: "uiClasses", isSignal: true, isRequired: false, transformFunction: null }, contentTemplate: { classPropertyName: "contentTemplate", publicName: "contentTemplate", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isShowLoadingPercentsPopup()) {\n @let _awsInstance = awsInstance();\n <div [class]=\"cardSkin()\" class=\"status-anchor\">\n @if (contentTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: slotContext }\"\n />\n } @else if (_awsInstance?.message) {\n <p>{{ _awsInstance?.message }}</p>\n } @else {\n <div [class]=\"messageSkin()\">\n <app-unreal-spinner [size]=\"30\" [strokeColor]=\"'#1F2937'\" />\n {{ smoothPercents() }}%\n </div>\n }\n </div>\n}\n", styles: ["app-stat-graph{height:30px;width:100%}.status-anchor{position:absolute;top:80%;left:50%;transform:translate(-50%,-50%);z-index:5;pointer-events:none}.status-box{display:flex;justify-content:center;align-items:center;width:auto;max-width:500px;margin:0;background:var(--unreal-surface-card, var(--src-surface-container-main, #fff));border:none;border-radius:var(--unreal-radius-pill, var(--src-border-rounded-full, 9999px));box-shadow:0 8px 20px #1718181f,0 3px 6px #17181814}.status-anchor p{padding:10px 15px;margin:0;text-align:center}.status-box__message{display:flex;align-items:center;padding:12px 20px 12px 16px;color:var(--unreal-text-main, var(--src-text-body-main, #1f2937));font-size:16px;font-weight:400;line-height:24px}.status-box__message .status-box__message_text{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}.status-box__message app-unreal-spinner{margin-right:12px}\n"], dependencies: [{ kind: "component", type: UnrealSpinnerComponent, selector: "app-unreal-spinner", inputs: ["size", "strokeWidth", "strokeColor", "data-testid", "ariaLabel"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
7911
8467
|
}
|
|
7912
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8468
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealStatusComponent, decorators: [{
|
|
7913
8469
|
type: Component,
|
|
7914
8470
|
args: [{ selector: 'app-unreal-status', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealSpinnerComponent, NgTemplateOutlet], template: "@if (isShowLoadingPercentsPopup()) {\n @let _awsInstance = awsInstance();\n <div [class]=\"cardSkin()\" class=\"status-anchor\">\n @if (contentTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: slotContext }\"\n />\n } @else if (_awsInstance?.message) {\n <p>{{ _awsInstance?.message }}</p>\n } @else {\n <div [class]=\"messageSkin()\">\n <app-unreal-spinner [size]=\"30\" [strokeColor]=\"'#1F2937'\" />\n {{ smoothPercents() }}%\n </div>\n }\n </div>\n}\n", styles: ["app-stat-graph{height:30px;width:100%}.status-anchor{position:absolute;top:80%;left:50%;transform:translate(-50%,-50%);z-index:5;pointer-events:none}.status-box{display:flex;justify-content:center;align-items:center;width:auto;max-width:500px;margin:0;background:var(--unreal-surface-card, var(--src-surface-container-main, #fff));border:none;border-radius:var(--unreal-radius-pill, var(--src-border-rounded-full, 9999px));box-shadow:0 8px 20px #1718181f,0 3px 6px #17181814}.status-anchor p{padding:10px 15px;margin:0;text-align:center}.status-box__message{display:flex;align-items:center;padding:12px 20px 12px 16px;color:var(--unreal-text-main, var(--src-text-body-main, #1f2937));font-size:16px;font-weight:400;line-height:24px}.status-box__message .status-box__message_text{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}.status-box__message app-unreal-spinner{margin-right:12px}\n"] }]
|
|
7915
8471
|
}], propDecorators: { uiClasses: [{ type: i0.Input, args: [{ isSignal: true, alias: "uiClasses", required: false }] }], contentTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentTemplate", required: false }] }] } });
|
|
@@ -7942,10 +8498,10 @@ class SafePipe {
|
|
|
7942
8498
|
// content instead of disabling framework security checks.
|
|
7943
8499
|
return (this.sanitizer.sanitize(context, value) ?? '');
|
|
7944
8500
|
}
|
|
7945
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7946
|
-
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.
|
|
8501
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SafePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
8502
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: SafePipe, isStandalone: true, name: "safe" }); }
|
|
7947
8503
|
}
|
|
7948
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8504
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SafePipe, decorators: [{
|
|
7949
8505
|
type: Pipe,
|
|
7950
8506
|
args: [{
|
|
7951
8507
|
name: 'safe',
|
|
@@ -8058,10 +8614,10 @@ class VideoStatsComponent {
|
|
|
8058
8614
|
elements: this.elementsToShow(),
|
|
8059
8615
|
}));
|
|
8060
8616
|
}
|
|
8061
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
8062
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
8617
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: VideoStatsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8618
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: VideoStatsComponent, isStandalone: true, selector: "app-video-stats", ngImport: i0, template: "@if (videoStatus() && viewportReady()) {\n <div class=\"settings-container\">\n <button (click)=\"toggle()\" class=\"gear-button\">Stats</button>\n <div (click)=\"toggle()\" [class.min]=\"collapsed()\" id=\"aggregatedStats\">\n <div class=\"forNerds\">\n <div (click)=\"$event.stopPropagation()\" class=\"static\">\n <li>\n <app-stat-graph\n [stat]=\"fpsTick()!\"\n label=\"FPS (higher is better)\"\n />\n </li>\n <li>\n <app-stat-graph\n [stat]=\"videoQP()!\"\n label=\"QP (lower is better)\"\n color=\"#D5ff07\"\n />\n </li>\n <li>\n <app-stat-graph\n [stat]=\"bitrateTick()!\"\n label=\"Bitrate\"\n color=\"#D57F07\"\n />\n </li>\n </div>\n <div>\n @for (graph of graphList(); track graph.key) {\n <li (click)=\"toggleGraph($event, graph.key, 0)\" class=\"graph\">\n <app-stat-graph\n [label]=\"graph.key\"\n [stat]=\"graph.stat()\"\n [color]=\"graph.color\"\n />\n </li>\n }\n </div>\n </div>\n\n @for (el of videoStatus(); track el.key + $index) {\n <div (click)=\"toggleGraph($event, el.key, el.value)\" class=\"stat\">\n <span>{{ el.key }}: </span>{{ el.value | json }}\n </div>\n }\n </div>\n </div>\n @if (!collapsed()) {\n <div [innerHTML]=\"ssData() | safe: 'html'\" class=\"ssInfo\"></div>\n }\n}\n", styles: [".settings-container{position:absolute;top:65px;left:10px;z-index:1000;bottom:10px}.gear-button{left:0;width:50px;position:absolute;background:none;cursor:pointer;font-size:10px;font-weight:500;border:1px solid;border-radius:9px;background:#0162cc;color:#fff;padding:4px}.gear-button>*{color:#fff;filter:drop-shadow(1px 1px 1px rgb(0,0,0))}#aggregatedStats{max-height:calc(100% - 25px);overflow-y:auto;margin-top:25px;left:20px;z-index:31;max-width:400px;padding:10px;background-color:#fff3;border:1px solid grey}#aggregatedStats>*{color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000}#aggregatedStats:empty{display:none}#aggregatedStats button{position:absolute;right:5px;top:5px}#aggregatedStats.min{display:none}#aggregatedStats .forNerds{width:100%}#aggregatedStats .forNerds li{list-style-type:none;height:60px}#aggregatedStats .forNerds li app-stat-graph{display:block;width:100%;height:100%}#aggregatedStats .stat span{font-weight:700}#aggregatedStats .stat,#aggregatedStats .graph{cursor:pointer}#aggregatedStats .static{pointer-events:all}.ssInfo{position:absolute;top:0;left:50%;transform:translate(-50%);color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000;text-align:center;width:80%;pointer-events:none}\n"], dependencies: [{ kind: "component", type: StatGraphComponent, selector: "app-stat-graph", inputs: ["label", "stat", "color", "tickStep"] }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "pipe", type: SafePipe, name: "safe" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
8063
8619
|
}
|
|
8064
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8620
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: VideoStatsComponent, decorators: [{
|
|
8065
8621
|
type: Component,
|
|
8066
8622
|
args: [{ selector: 'app-video-stats', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StatGraphComponent, JsonPipe, SafePipe], template: "@if (videoStatus() && viewportReady()) {\n <div class=\"settings-container\">\n <button (click)=\"toggle()\" class=\"gear-button\">Stats</button>\n <div (click)=\"toggle()\" [class.min]=\"collapsed()\" id=\"aggregatedStats\">\n <div class=\"forNerds\">\n <div (click)=\"$event.stopPropagation()\" class=\"static\">\n <li>\n <app-stat-graph\n [stat]=\"fpsTick()!\"\n label=\"FPS (higher is better)\"\n />\n </li>\n <li>\n <app-stat-graph\n [stat]=\"videoQP()!\"\n label=\"QP (lower is better)\"\n color=\"#D5ff07\"\n />\n </li>\n <li>\n <app-stat-graph\n [stat]=\"bitrateTick()!\"\n label=\"Bitrate\"\n color=\"#D57F07\"\n />\n </li>\n </div>\n <div>\n @for (graph of graphList(); track graph.key) {\n <li (click)=\"toggleGraph($event, graph.key, 0)\" class=\"graph\">\n <app-stat-graph\n [label]=\"graph.key\"\n [stat]=\"graph.stat()\"\n [color]=\"graph.color\"\n />\n </li>\n }\n </div>\n </div>\n\n @for (el of videoStatus(); track el.key + $index) {\n <div (click)=\"toggleGraph($event, el.key, el.value)\" class=\"stat\">\n <span>{{ el.key }}: </span>{{ el.value | json }}\n </div>\n }\n </div>\n </div>\n @if (!collapsed()) {\n <div [innerHTML]=\"ssData() | safe: 'html'\" class=\"ssInfo\"></div>\n }\n}\n", styles: [".settings-container{position:absolute;top:65px;left:10px;z-index:1000;bottom:10px}.gear-button{left:0;width:50px;position:absolute;background:none;cursor:pointer;font-size:10px;font-weight:500;border:1px solid;border-radius:9px;background:#0162cc;color:#fff;padding:4px}.gear-button>*{color:#fff;filter:drop-shadow(1px 1px 1px rgb(0,0,0))}#aggregatedStats{max-height:calc(100% - 25px);overflow-y:auto;margin-top:25px;left:20px;z-index:31;max-width:400px;padding:10px;background-color:#fff3;border:1px solid grey}#aggregatedStats>*{color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000}#aggregatedStats:empty{display:none}#aggregatedStats button{position:absolute;right:5px;top:5px}#aggregatedStats.min{display:none}#aggregatedStats .forNerds{width:100%}#aggregatedStats .forNerds li{list-style-type:none;height:60px}#aggregatedStats .forNerds li app-stat-graph{display:block;width:100%;height:100%}#aggregatedStats .stat span{font-weight:700}#aggregatedStats .stat,#aggregatedStats .graph{cursor:pointer}#aggregatedStats .static{pointer-events:all}.ssInfo{position:absolute;top:0;left:50%;transform:translate(-50%);color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000;text-align:center;width:80%;pointer-events:none}\n"] }]
|
|
8067
8623
|
}], ctorParameters: () => [] });
|
|
@@ -8123,10 +8679,10 @@ class ResumeStreamButtonComponent {
|
|
|
8123
8679
|
disconnect() {
|
|
8124
8680
|
this.isSecondStart.set(true);
|
|
8125
8681
|
}
|
|
8126
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
8127
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
8682
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ResumeStreamButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8683
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: ResumeStreamButtonComponent, isStandalone: true, selector: "app-resume-stream-button", inputs: { uiClasses: { classPropertyName: "uiClasses", publicName: "uiClasses", isSignal: true, isRequired: false, transformFunction: null }, contentTemplate: { classPropertyName: "contentTemplate", publicName: "contentTemplate", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isShowResumeButton()) {\n <div [class]=\"cardSkin()\" class=\"resume-anchor\">\n @if (contentTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: slotContext }\"\n />\n } @else {\n @if (isSecondStart()) {\n <div [class]=\"textSkin()\">\n Your stream {{ isAfkDisconnect() ? 'has been' : 'is' }} paused due to\n inactivity\n </div>\n }\n\n <app-unreal-button\n (clicked)=\"connect()\"\n [fullWidth]=\"true\"\n [data-testid]=\"'connect-button'\"\n [class]=\"buttonSkin()\"\n size=\"lg\"\n weight=\"primary\"\n >\n {{ isSecondStart() ? 'Resume' : 'Start' }}\n </app-unreal-button>\n }\n </div>\n}\n", styles: [".resume-anchor{position:absolute;bottom:0;left:50%;transform:translate(-50%,-50%);z-index:6}.resume-box{padding:16px;gap:12px;display:flex;flex-direction:column;align-items:center;border-radius:var(--unreal-radius-card, var(--src-border-rounded-parent, 8px));background:var(--unreal-surface-card, var(--src-surface-container-main, #fff));box-shadow:var(--unreal-shadow-card, 0 26px 80px 0 rgba(0, 0, 0, .2), 0 0 1px 0 rgba(0, 0, 0, .2))}.connect-button{width:100%}.resume-box__text{color:var(--unreal-text-secondary, var(--src-color-grey-500, #6b7280));text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:14px;font-style:normal;font-weight:400;line-height:24px}\n"], dependencies: [{ kind: "component", type: UnrealButtonComponent, selector: "app-unreal-button", inputs: ["type", "weight", "size", "fullWidth", "isDisabled", "data-testid", "ariaLabel"], outputs: ["clicked"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
8128
8684
|
}
|
|
8129
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8685
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ResumeStreamButtonComponent, decorators: [{
|
|
8130
8686
|
type: Component,
|
|
8131
8687
|
args: [{ selector: 'app-resume-stream-button', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent, NgTemplateOutlet], template: "@if (isShowResumeButton()) {\n <div [class]=\"cardSkin()\" class=\"resume-anchor\">\n @if (contentTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: slotContext }\"\n />\n } @else {\n @if (isSecondStart()) {\n <div [class]=\"textSkin()\">\n Your stream {{ isAfkDisconnect() ? 'has been' : 'is' }} paused due to\n inactivity\n </div>\n }\n\n <app-unreal-button\n (clicked)=\"connect()\"\n [fullWidth]=\"true\"\n [data-testid]=\"'connect-button'\"\n [class]=\"buttonSkin()\"\n size=\"lg\"\n weight=\"primary\"\n >\n {{ isSecondStart() ? 'Resume' : 'Start' }}\n </app-unreal-button>\n }\n </div>\n}\n", styles: [".resume-anchor{position:absolute;bottom:0;left:50%;transform:translate(-50%,-50%);z-index:6}.resume-box{padding:16px;gap:12px;display:flex;flex-direction:column;align-items:center;border-radius:var(--unreal-radius-card, var(--src-border-rounded-parent, 8px));background:var(--unreal-surface-card, var(--src-surface-container-main, #fff));box-shadow:var(--unreal-shadow-card, 0 26px 80px 0 rgba(0, 0, 0, .2), 0 0 1px 0 rgba(0, 0, 0, .2))}.connect-button{width:100%}.resume-box__text{color:var(--unreal-text-secondary, var(--src-color-grey-500, #6b7280));text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:14px;font-style:normal;font-weight:400;line-height:24px}\n"] }]
|
|
8132
8688
|
}], ctorParameters: () => [], propDecorators: { uiClasses: [{ type: i0.Input, args: [{ isSignal: true, alias: "uiClasses", required: false }] }], contentTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentTemplate", required: false }] }] } });
|
|
@@ -8193,10 +8749,10 @@ class IntroSrcComponent {
|
|
|
8193
8749
|
sourceElement.addEventListener('error', () => this.#store.dispatch(resetIntroSrc()));
|
|
8194
8750
|
videoContainer.appendChild(videoElement);
|
|
8195
8751
|
}
|
|
8196
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
8197
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.
|
|
8752
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: IntroSrcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8753
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: IntroSrcComponent, isStandalone: true, selector: "app-intro-src", viewQueries: [{ propertyName: "videoElement", first: true, predicate: ["videoPlayerCover"], descendants: true, isSignal: true }], ngImport: i0, template: "@let image = imageIntroSrc();\n@if (image) {\n <div class=\"backImage\">\n <img (error)=\"loadingImageError()\" [ngSrc]=\"image\" fill alt=\"imageSrc\" />\n </div>\n} @else if (videoIntroSrc()) {\n <div #videoPlayerCover class=\"backVideo\"></div>\n}\n", styles: [".backVideo{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backVideo video{position:absolute;width:100%;height:100%;object-fit:cover}.backImage{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backImage img{position:absolute;width:100%;height:100%;object-fit:cover}\n"], dependencies: [{ kind: "directive", type: NgOptimizedImage, selector: "img[ngSrc]", inputs: ["ngSrc", "ngSrcset", "sizes", "width", "height", "decoding", "loading", "priority", "loaderParams", "disableOptimizedSrcset", "fill", "placeholder", "placeholderConfig", "src", "srcset"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
8198
8754
|
}
|
|
8199
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8755
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: IntroSrcComponent, decorators: [{
|
|
8200
8756
|
type: Component,
|
|
8201
8757
|
args: [{ selector: 'app-intro-src', imports: [NgOptimizedImage], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let image = imageIntroSrc();\n@if (image) {\n <div class=\"backImage\">\n <img (error)=\"loadingImageError()\" [ngSrc]=\"image\" fill alt=\"imageSrc\" />\n </div>\n} @else if (videoIntroSrc()) {\n <div #videoPlayerCover class=\"backVideo\"></div>\n}\n", styles: [".backVideo{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backVideo video{position:absolute;width:100%;height:100%;object-fit:cover}.backImage{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backImage img{position:absolute;width:100%;height:100%;object-fit:cover}\n"] }]
|
|
8202
8758
|
}], ctorParameters: () => [], propDecorators: { videoElement: [{ type: i0.ViewChild, args: ['videoPlayerCover', { isSignal: true }] }] } });
|
|
@@ -8427,10 +8983,10 @@ class UnrealSceneComponent {
|
|
|
8427
8983
|
},
|
|
8428
8984
|
});
|
|
8429
8985
|
}
|
|
8430
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
8431
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.2", type: UnrealSceneComponent, isStandalone: true, selector: "app-unreal-scene", inputs: { useContainerAsSizeProvider: { classPropertyName: "useContainerAsSizeProvider", publicName: "useContainerAsSizeProvider", isSignal: true, isRequired: false, transformFunction: null }, isStudio: { classPropertyName: "isStudio", publicName: "isStudio", isSignal: true, isRequired: false, transformFunction: null }, resolutionSize: { classPropertyName: "resolutionSize", publicName: "resolutionSize", isSignal: true, isRequired: false, transformFunction: null }, uiClasses: { classPropertyName: "uiClasses", publicName: "uiClasses", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changeMouseOverScene: "changeMouseOverScene" }, host: { listeners: { "mouseover": "onMouseOver()", "mouseout": "onMouseOut()", "contextmenu": "onContextMenu($event)" } }, queries: [{ propertyName: "resumeSlot", first: true, predicate: UnrealResumeSlotDirective, descendants: true, isSignal: true }, { propertyName: "afkSlot", first: true, predicate: UnrealAfkSlotDirective, descendants: true, isSignal: true }, { propertyName: "statusSlot", first: true, predicate: UnrealStatusSlotDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "videoElement", first: true, predicate: ["videoContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"frame unreal-container\">\n <div #videoContainer id=\"player\"></div>\n\n <app-intro-src />\n <app-image-loading-src />\n <app-freeze-frame />\n <app-resume-stream-button\n [uiClasses]=\"uiClasses()\"\n [contentTemplate]=\"resumeSlot()?.template ?? null\"\n />\n <app-unreal-status\n [uiClasses]=\"uiClasses()\"\n [contentTemplate]=\"statusSlot()?.template ?? null\"\n />\n <app-afk-timeout-modal\n [uiClasses]=\"uiClasses()\"\n [contentTemplate]=\"afkSlot()?.template ?? null\"\n />\n\n <ng-content select=\"app-pdf\"></ng-content>\n <ng-content select=\"app-show-case\"></ng-content>\n\n @if (isDevMode) {\n <app-video-stats />\n }\n</div>\n", styles: [".unreal-container{position:absolute;top:0;left:0;width:100%;height:100%;background-color:#fff}.unreal-container #player{position:absolute;width:100%;height:100%;display:flex;justify-content:center;align-items:center;overflow:hidden}.unreal-container.select{cursor:url('data:image/svg+xml,<svg width=\"24\" height=\"24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M15.15 21.375a1.423 1.423 0 0 1-1.15.063 1.487 1.487 0 0 1-.85-.788l-3-6.45-2.325 3.25c-.283.4-.658.525-1.125.375-.467-.15-.7-.466-.7-.95V4.05c0-.417.188-.717.563-.9.375-.183.729-.142 1.062.125l10.1 7.95c.383.284.496.65.337 1.1-.158.45-.479.675-.962.675h-4.2l2.975 6.375c.183.384.204.767.063 1.15a1.487 1.487 0 0 1-.788.85Z\" fill=\"%23000\"/><path d=\"m12.697 20.861.002.005c.237.495.617.852 1.128 1.04.515.191 1.039.16 1.539-.08a1.987 1.987 0 0 0 1.04-1.128 1.922 1.922 0 0 0-.079-1.536v-.003L13.684 13.5H17.1c.32 0 .628-.075.89-.26.263-.184.438-.447.544-.749.106-.3.135-.617.04-.925a1.458 1.458 0 0 0-.545-.738L7.936 2.883a1.51 1.51 0 0 0-.768-.336 1.471 1.471 0 0 0-.825.154 1.495 1.495 0 0 0-.626.547 1.492 1.492 0 0 0-.217.802v12.825c0 .324.08.634.272.897.193.261.467.43.775.53.31.099.632.12.942.016.31-.103.555-.313.743-.578h.001l1.825-2.552 2.639 5.673Z\" stroke=\"%23fff\" stroke-opacity=\".7\"/></svg>') 6 2,auto}.unreal-container.orbit{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.998 21.6c-1.966 0-3.737-.53-5.312-1.588-1.575-1.058-2.738-2.437-3.488-4.137a.852.852 0 0 1 .013-.713.867.867 0 0 1 .512-.487.86.86 0 0 1 .688.037c.225.109.387.28.487.513.617 1.35 1.559 2.45 2.825 3.3 1.267.85 2.692 1.275 4.275 1.275 1.384 0 2.646-.33 3.788-.988a7.985 7.985 0 0 0 2.762-2.612h-.85a.873.873 0 0 1-.64-.257.863.863 0 0 1-.26-.638.88.88 0 0 1 .26-.643.864.864 0 0 1 .64-.262h3c.255 0 .47.086.642.259a.87.87 0 0 1 .258.64v3a.874.874 0 0 1-.257.642.863.863 0 0 1-.637.259.88.88 0 0 1-.643-.259.865.865 0 0 1-.263-.641v-.725a9.95 9.95 0 0 1-3.35 2.925c-1.35.733-2.833 1.1-4.45 1.1Zm0-17.4c-1.383 0-2.645.33-3.787.987A7.985 7.985 0 0 0 5.448 7.8h.85c.255 0 .47.086.642.257a.863.863 0 0 1 .258.638.88.88 0 0 1-.258.642.864.864 0 0 1-.642.263h-3a.87.87 0 0 1-.64-.259.87.87 0 0 1-.26-.641v-3c0-.255.086-.469.258-.641a.863.863 0 0 1 .637-.26.88.88 0 0 1 .643.26.864.864 0 0 1 .262.64v.726A9.95 9.95 0 0 1 7.548 3.5c1.35-.733 2.834-1.1 4.45-1.1 2 0 3.788.542 5.363 1.625 1.575 1.083 2.736 2.49 3.482 4.22a.724.724 0 0 1-.045.646.926.926 0 0 1-.525.437.87.87 0 0 1-.687-.04.977.977 0 0 1-.488-.513c-.616-1.35-1.558-2.45-2.825-3.3-1.266-.85-2.691-1.275-4.275-1.275Zm0 10.8a2.893 2.893 0 0 1-2.125-.875A2.893 2.893 0 0 1 8.998 12c0-.833.292-1.542.875-2.125A2.893 2.893 0 0 1 11.998 9c.834 0 1.542.292 2.125.875.584.583.875 1.292.875 2.125s-.291 1.542-.875 2.125a2.893 2.893 0 0 1-2.125.875Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"m2.739 16.072.002.005c.789 1.788 2.014 3.24 3.666 4.35 1.66 1.116 3.53 1.673 5.591 1.673 1.696 0 3.262-.386 4.69-1.16a10.54 10.54 0 0 0 2.714-2.097c.069.167.171.32.308.454.272.268.613.403.994.403.38 0 .722-.135.992-.406s.402-.614.402-.994v-3c0-.381-.134-.724-.405-.995a1.37 1.37 0 0 0-.995-.405h-3c-.383 0-.727.137-.997.411a1.38 1.38 0 0 0-.403.994c0 .38.135.723.407.992.238.237.532.369.858.397a7.552 7.552 0 0 1-2.027 1.685c-1.062.613-2.237.92-3.538.92-1.488 0-2.815-.397-3.996-1.19-1.19-.798-2.07-1.826-2.647-3.087-.147-.34-.393-.6-.727-.76a1.36 1.36 0 0 0-1.073-.058c-.37.133-.64.397-.8.754a1.351 1.351 0 0 0-.016 1.114Zm4.553-8.37a1.36 1.36 0 0 0-.858-.396A7.552 7.552 0 0 1 8.46 5.62c1.062-.613 2.237-.921 3.537-.921 1.489 0 2.816.398 3.997 1.19 1.19.8 2.07 1.827 2.646 3.088.148.34.394.6.728.76a1.37 1.37 0 0 0 1.068.063c.347-.12.62-.346.799-.668.187-.338.215-.71.072-1.072l-.003-.007-.003-.007c-.784-1.818-2.006-3.298-3.658-4.434C15.982 2.47 14.094 1.9 11.998 1.9c-1.695 0-3.261.385-4.688 1.16a10.536 10.536 0 0 0-2.715 2.096 1.364 1.364 0 0 0-.308-.453 1.38 1.38 0 0 0-.994-.403c-.38 0-.722.135-.992.406s-.403.614-.403.994v3c0 .38.135.724.406.995.27.27.614.405.994.405h3c.384 0 .727-.137.998-.412a1.38 1.38 0 0 0 .402-.993c0-.38-.135-.723-.406-.992ZM9.52 14.48a3.393 3.393 0 0 0 2.478 1.02c.965 0 1.8-.342 2.479-1.02a3.392 3.392 0 0 0 1.021-2.48c0-.963-.343-1.8-1.021-2.478A3.392 3.392 0 0 0 11.998 8.5c-.964 0-1.8.343-2.478 1.021A3.392 3.392 0 0 0 8.498 12c0 .964.344 1.8 1.022 2.479Z\"/></svg>') 12 12,auto}.unreal-container.pan{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.997 10.075a1.01 1.01 0 0 1-.738-.313 1.008 1.008 0 0 1-.312-.737V6.15l-.95.95a.998.998 0 0 1-.763.312 1.09 1.09 0 0 1-.763-.337 1.06 1.06 0 0 1-.324-.775c0-.3.108-.558.324-.775l2.776-2.775c.117-.116.237-.2.362-.25a1.04 1.04 0 0 1 .775 0c.125.05.246.134.363.25l2.8 2.8c.216.217.32.47.313.762a1.096 1.096 0 0 1-.338.763 1.058 1.058 0 0 1-.775.325c-.3 0-.558-.108-.775-.325l-.925-.925v2.875c0 .283-.104.53-.312.737a1.01 1.01 0 0 1-.738.313Zm0 11.5a1.04 1.04 0 0 1-.388-.075 1.103 1.103 0 0 1-.362-.25l-2.8-2.8a1.002 1.002 0 0 1-.313-.762c.009-.292.121-.546.337-.763.217-.217.475-.325.775-.325.3 0 .559.108.775.325l.926.925v-2.875c0-.283.104-.529.312-.737a1.01 1.01 0 0 1 .738-.313c.283 0 .529.104.738.313.208.208.312.454.312.737v2.875l.95-.95a.998.998 0 0 1 .762-.312c.292.008.546.12.763.337.216.217.324.475.324.775 0 .3-.108.559-.324.775l-2.775 2.775c-.117.116-.238.2-.363.25a1.04 1.04 0 0 1-.387.075Zm4.925-6.05a1.058 1.058 0 0 1-.326-.774c0-.3.109-.559.326-.776l.925-.925H14.97c-.283 0-.528-.104-.736-.312a1.01 1.01 0 0 1-.313-.738c0-.283.104-.53.313-.738.208-.208.453-.312.737-.312h2.875l-.95-.95a.998.998 0 0 1-.313-.762 1.09 1.09 0 0 1 .338-.764 1.06 1.06 0 0 1 .775-.324c.3 0 .558.108.775.324l2.774 2.776c.117.117.2.238.251.363a1.04 1.04 0 0 1 0 .775c-.05.124-.134.245-.25.362l-2.8 2.8c-.217.216-.471.32-.762.313a1.096 1.096 0 0 1-.763-.337Zm-11.4 0L2.746 12.75a1.103 1.103 0 0 1-.25-.362 1.04 1.04 0 0 1 0-.775c.05-.125.133-.246.25-.363l2.8-2.8c.216-.216.47-.32.762-.313.292.01.546.121.763.337.217.217.325.476.325.776 0 .3-.108.558-.325.775l-.925.925h2.875c.283 0 .529.104.737.312.208.209.313.455.313.738s-.105.53-.313.738a1.008 1.008 0 0 1-.737.312H6.147l.95.95c.217.217.32.471.312.762a1.09 1.09 0 0 1-.337.764 1.06 1.06 0 0 1-.775.324c-.3 0-.559-.108-.776-.324Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M9.22 7.912c.436.013.821-.15 1.13-.458l.097-.097v1.668c0 .422.16.793.458 1.09.298.299.67.46 1.092.46.422 0 .793-.161 1.091-.46.298-.297.459-.668.459-1.09V7.357l.071.072c.309.308.693.471 1.13.471.435 0 .82-.163 1.128-.471.301-.303.47-.676.483-1.102v-.001a1.501 1.501 0 0 0-.46-1.13l-2.799-2.8a1.6 1.6 0 0 0-.528-.36l-.003-.001a1.54 1.54 0 0 0-1.145 0l-.002.001a1.6 1.6 0 0 0-.529.36L8.118 5.172l-.001.001a1.56 1.56 0 0 0-.47 1.128c0 .435.163.82.47 1.128.303.303.676.472 1.103.484Zm0 0 .014-.5-.015.5Zm-1.311 6.865a1.497 1.497 0 0 0-.458-1.13l-.097-.097h1.668c.421 0 .793-.16 1.09-.458.298-.299.46-.67.46-1.092a1.51 1.51 0 0 0-.46-1.091 1.507 1.507 0 0 0-1.09-.459H7.354l.071-.072c.309-.308.472-.692.472-1.128 0-.436-.163-.82-.472-1.13a1.596 1.596 0 0 0-1.101-.482h-.002a1.501 1.501 0 0 0-1.129.459l-2.8 2.8a1.6 1.6 0 0 0-.36.528l-.001.003a1.54 1.54 0 0 0 0 1.144v.003c.081.2.208.375.362.529l2.774 2.775c.309.308.693.47 1.129.47.435 0 .82-.162 1.128-.47.303-.302.472-.676.484-1.102Zm0 0-.5-.014.5.015v-.001Zm3.038-8.627-.5.5.5.207V6.15Zm.475 15.814.002.001a1.54 1.54 0 0 0 1.145 0h.002c.2-.081.375-.208.53-.362l2.775-2.774a1.56 1.56 0 0 0 .47-1.129c0-.435-.162-.82-.47-1.128a1.589 1.589 0 0 0-1.103-.484 1.497 1.497 0 0 0-1.13.458l-.096.097v-1.668c0-.421-.161-.793-.459-1.09a1.509 1.509 0 0 0-1.091-.46c-.422 0-.794.161-1.092.46a1.507 1.507 0 0 0-.458 1.09v1.668l-.072-.072a1.558 1.558 0 0 0-1.129-.471c-.436 0-.82.163-1.128.471l-.001.001c-.301.302-.47.675-.483 1.101v.001c-.012.437.151.821.46 1.13l2.8 2.8c.153.153.328.28.528.36Zm5.146-6.085c.303.302.676.47 1.102.484a1.5 1.5 0 0 0 1.13-.46l2.8-2.8a1.6 1.6 0 0 0 .36-.528l.002-.003a1.54 1.54 0 0 0 0-1.144l-.001-.003a1.6 1.6 0 0 0-.361-.529l-2.774-2.775h-.001a1.56 1.56 0 0 0-1.128-.47c-.436 0-.82.162-1.128.47h-.001a1.59 1.59 0 0 0-.484 1.102c-.012.437.15.822.459 1.13l.097.097h-1.668c-.422 0-.793.16-1.09.459-.299.298-.46.67-.46 1.091 0 .422.161.793.46 1.092.297.297.668.458 1.09.458h1.668l-.072.072a1.558 1.558 0 0 0-.472 1.129c0 .435.164.82.472 1.128ZM6.147 13.05l.5.5.207-.5h-.707Z\"/></svg>') 12 12,auto}.unreal-container.dolly{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><mask id=\"a\" width=\"24\" height=\"24\" x=\"0\" y=\"0\" maskUnits=\"userSpaceOnUse\" style=\"mask-type:alpha\"><path fill=\"%23127392\" d=\"M0 0h24v24H0z\"/></mask><g mask=\"url(%23a)\"><path fill=\"%23000\" d=\"M12.002 20.575a1.026 1.026 0 0 1-.75-.325l-2.55-2.55a.933.933 0 0 1-.287-.713c.008-.275.113-.513.313-.713.2-.2.441-.3.725-.3.283 0 .524.1.724.3l.776.776V6.95l-.8.8c-.2.2-.438.296-.712.288a1.018 1.018 0 0 1-.713-.312c-.2-.2-.3-.442-.3-.726s.1-.525.3-.725l2.524-2.525a1.026 1.026 0 0 1 1.5 0l2.55 2.55c.2.2.296.438.289.713a1.023 1.023 0 0 1-.314.713c-.2.2-.441.3-.724.3a.988.988 0 0 1-.725-.3l-.775-.776v10.1l.8-.8c.2-.2.437-.296.712-.288.275.008.512.112.712.312.2.2.3.442.3.726s-.1.525-.3.725l-2.524 2.525a1.026 1.026 0 0 1-.75.325Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M13.553 8.153c.28.245.62.373 1 .373.415 0 .784-.153 1.078-.447.287-.287.446-.644.46-1.05v-.002a1.432 1.432 0 0 0-.435-1.08l-2.55-2.55-.354.353.354-.354a1.526 1.526 0 0 0-2.207 0L8.374 5.921A1.487 1.487 0 0 0 7.928 7c0 .416.152.785.446 1.08.288.287.645.446 1.052.457l4.127-.384Zm0 0v7.693m0-7.693a1.667 1.667 0 0 1-.079-.074l-3.021.075v7.693a1.482 1.482 0 0 0-1-.373c-.416 0-.785.153-1.079.447a1.522 1.522 0 0 0-.46 1.05v.002c-.011.417.14.786.435 1.08l2.55 2.55a1.527 1.527 0 0 0 2.207 0l2.525-2.524c.294-.294.446-.663.446-1.079 0-.416-.152-.785-.446-1.08a1.518 1.518 0 0 0-1.052-.457m0 0-.014.5.014-.5Zm0 0a1.424 1.424 0 0 0-1.027.383m0 0a1.583 1.583 0 0 0-.053.05l.354.354m-.3-.404v.104l.3.3m0 0-.3-.3v.6l.3-.3Z\"/></g></svg>%0A') 12 12,auto}.unreal-container.disabled:before{content:\"\";position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}#playerUI{position:absolute;z-index:10;width:100%}#statsContainer{display:none;text-align:left;background-color:#000c}#stats{padding:6px;font-weight:700;font-size:14px;color:#0f0}canvas{position:absolute;image-rendering:crisp-edges}#overlay{position:absolute;top:0;right:2%;z-index:100;padding:4px;border-top-width:0;-webkit-border-bottom-right-radius:5px;-moz-border-radius-bottomright:5px;border-bottom-right-radius:5px;-webkit-border-bottom-left-radius:5px;-moz-border-radius-bottomleft:5px;border-bottom-left-radius:5px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-touch-callout:none}.overlay{font-weight:lighter;font-family:var(--src-font-family-body, system-ui, sans-serif)}#overlayButton:hover{cursor:pointer}#overlayButton{font-size:40px;text-align:right}#overlaySettings{display:none;width:300px;padding:4px}#videoMessageOverlay{position:absolute;z-index:20;width:100%;margin:auto;font-size:1.8em;font-family:var(--src-font-family-body, system-ui, sans-serif)}#playButton{display:inline-block;height:auto}img#playButton{width:10%;max-width:241px}#UIInteraction{position:fixed}#UIInteractionButtonBoundary{padding:2px}#UIInteractionButton{cursor:pointer}#hiddenInput{position:absolute;left:-10%;width:0;opacity:0}#editTextButton{position:absolute;width:40px;height:40px}\n"], dependencies: [{ kind: "component", type: AfkTimeoutModalComponent, selector: "app-afk-timeout-modal", inputs: ["uiClasses", "contentTemplate"] }, { kind: "component", type: UnrealStatusComponent, selector: "app-unreal-status", inputs: ["uiClasses", "contentTemplate"] }, { kind: "component", type: FreezeFrameComponent, selector: "app-freeze-frame" }, { kind: "component", type: VideoStatsComponent, selector: "app-video-stats" }, { kind: "component", type: ResumeStreamButtonComponent, selector: "app-resume-stream-button", inputs: ["uiClasses", "contentTemplate"] }, { kind: "component", type: ImageLoadingSrcComponent, selector: "app-image-loading-src" }, { kind: "component", type: IntroSrcComponent, selector: "app-intro-src" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
8986
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealSceneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8987
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: UnrealSceneComponent, isStandalone: true, selector: "app-unreal-scene", inputs: { useContainerAsSizeProvider: { classPropertyName: "useContainerAsSizeProvider", publicName: "useContainerAsSizeProvider", isSignal: true, isRequired: false, transformFunction: null }, isStudio: { classPropertyName: "isStudio", publicName: "isStudio", isSignal: true, isRequired: false, transformFunction: null }, resolutionSize: { classPropertyName: "resolutionSize", publicName: "resolutionSize", isSignal: true, isRequired: false, transformFunction: null }, uiClasses: { classPropertyName: "uiClasses", publicName: "uiClasses", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changeMouseOverScene: "changeMouseOverScene" }, host: { listeners: { "mouseover": "onMouseOver()", "mouseout": "onMouseOut()", "contextmenu": "onContextMenu($event)" } }, queries: [{ propertyName: "resumeSlot", first: true, predicate: UnrealResumeSlotDirective, descendants: true, isSignal: true }, { propertyName: "afkSlot", first: true, predicate: UnrealAfkSlotDirective, descendants: true, isSignal: true }, { propertyName: "statusSlot", first: true, predicate: UnrealStatusSlotDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "videoElement", first: true, predicate: ["videoContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"frame unreal-container\">\n <div #videoContainer id=\"player\"></div>\n\n <app-intro-src />\n <app-image-loading-src />\n <app-freeze-frame />\n <app-resume-stream-button\n [uiClasses]=\"uiClasses()\"\n [contentTemplate]=\"resumeSlot()?.template ?? null\"\n />\n <app-unreal-status\n [uiClasses]=\"uiClasses()\"\n [contentTemplate]=\"statusSlot()?.template ?? null\"\n />\n <app-afk-timeout-modal\n [uiClasses]=\"uiClasses()\"\n [contentTemplate]=\"afkSlot()?.template ?? null\"\n />\n\n <ng-content select=\"app-pdf\"></ng-content>\n <ng-content select=\"app-show-case\"></ng-content>\n\n @if (isDevMode) {\n <app-video-stats />\n }\n</div>\n", styles: [".unreal-container{position:absolute;top:0;left:0;width:100%;height:100%;background-color:#fff}.unreal-container #player{position:absolute;width:100%;height:100%;display:flex;justify-content:center;align-items:center;overflow:hidden}.unreal-container.select{cursor:url('data:image/svg+xml,<svg width=\"24\" height=\"24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M15.15 21.375a1.423 1.423 0 0 1-1.15.063 1.487 1.487 0 0 1-.85-.788l-3-6.45-2.325 3.25c-.283.4-.658.525-1.125.375-.467-.15-.7-.466-.7-.95V4.05c0-.417.188-.717.563-.9.375-.183.729-.142 1.062.125l10.1 7.95c.383.284.496.65.337 1.1-.158.45-.479.675-.962.675h-4.2l2.975 6.375c.183.384.204.767.063 1.15a1.487 1.487 0 0 1-.788.85Z\" fill=\"%23000\"/><path d=\"m12.697 20.861.002.005c.237.495.617.852 1.128 1.04.515.191 1.039.16 1.539-.08a1.987 1.987 0 0 0 1.04-1.128 1.922 1.922 0 0 0-.079-1.536v-.003L13.684 13.5H17.1c.32 0 .628-.075.89-.26.263-.184.438-.447.544-.749.106-.3.135-.617.04-.925a1.458 1.458 0 0 0-.545-.738L7.936 2.883a1.51 1.51 0 0 0-.768-.336 1.471 1.471 0 0 0-.825.154 1.495 1.495 0 0 0-.626.547 1.492 1.492 0 0 0-.217.802v12.825c0 .324.08.634.272.897.193.261.467.43.775.53.31.099.632.12.942.016.31-.103.555-.313.743-.578h.001l1.825-2.552 2.639 5.673Z\" stroke=\"%23fff\" stroke-opacity=\".7\"/></svg>') 6 2,auto}.unreal-container.orbit{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.998 21.6c-1.966 0-3.737-.53-5.312-1.588-1.575-1.058-2.738-2.437-3.488-4.137a.852.852 0 0 1 .013-.713.867.867 0 0 1 .512-.487.86.86 0 0 1 .688.037c.225.109.387.28.487.513.617 1.35 1.559 2.45 2.825 3.3 1.267.85 2.692 1.275 4.275 1.275 1.384 0 2.646-.33 3.788-.988a7.985 7.985 0 0 0 2.762-2.612h-.85a.873.873 0 0 1-.64-.257.863.863 0 0 1-.26-.638.88.88 0 0 1 .26-.643.864.864 0 0 1 .64-.262h3c.255 0 .47.086.642.259a.87.87 0 0 1 .258.64v3a.874.874 0 0 1-.257.642.863.863 0 0 1-.637.259.88.88 0 0 1-.643-.259.865.865 0 0 1-.263-.641v-.725a9.95 9.95 0 0 1-3.35 2.925c-1.35.733-2.833 1.1-4.45 1.1Zm0-17.4c-1.383 0-2.645.33-3.787.987A7.985 7.985 0 0 0 5.448 7.8h.85c.255 0 .47.086.642.257a.863.863 0 0 1 .258.638.88.88 0 0 1-.258.642.864.864 0 0 1-.642.263h-3a.87.87 0 0 1-.64-.259.87.87 0 0 1-.26-.641v-3c0-.255.086-.469.258-.641a.863.863 0 0 1 .637-.26.88.88 0 0 1 .643.26.864.864 0 0 1 .262.64v.726A9.95 9.95 0 0 1 7.548 3.5c1.35-.733 2.834-1.1 4.45-1.1 2 0 3.788.542 5.363 1.625 1.575 1.083 2.736 2.49 3.482 4.22a.724.724 0 0 1-.045.646.926.926 0 0 1-.525.437.87.87 0 0 1-.687-.04.977.977 0 0 1-.488-.513c-.616-1.35-1.558-2.45-2.825-3.3-1.266-.85-2.691-1.275-4.275-1.275Zm0 10.8a2.893 2.893 0 0 1-2.125-.875A2.893 2.893 0 0 1 8.998 12c0-.833.292-1.542.875-2.125A2.893 2.893 0 0 1 11.998 9c.834 0 1.542.292 2.125.875.584.583.875 1.292.875 2.125s-.291 1.542-.875 2.125a2.893 2.893 0 0 1-2.125.875Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"m2.739 16.072.002.005c.789 1.788 2.014 3.24 3.666 4.35 1.66 1.116 3.53 1.673 5.591 1.673 1.696 0 3.262-.386 4.69-1.16a10.54 10.54 0 0 0 2.714-2.097c.069.167.171.32.308.454.272.268.613.403.994.403.38 0 .722-.135.992-.406s.402-.614.402-.994v-3c0-.381-.134-.724-.405-.995a1.37 1.37 0 0 0-.995-.405h-3c-.383 0-.727.137-.997.411a1.38 1.38 0 0 0-.403.994c0 .38.135.723.407.992.238.237.532.369.858.397a7.552 7.552 0 0 1-2.027 1.685c-1.062.613-2.237.92-3.538.92-1.488 0-2.815-.397-3.996-1.19-1.19-.798-2.07-1.826-2.647-3.087-.147-.34-.393-.6-.727-.76a1.36 1.36 0 0 0-1.073-.058c-.37.133-.64.397-.8.754a1.351 1.351 0 0 0-.016 1.114Zm4.553-8.37a1.36 1.36 0 0 0-.858-.396A7.552 7.552 0 0 1 8.46 5.62c1.062-.613 2.237-.921 3.537-.921 1.489 0 2.816.398 3.997 1.19 1.19.8 2.07 1.827 2.646 3.088.148.34.394.6.728.76a1.37 1.37 0 0 0 1.068.063c.347-.12.62-.346.799-.668.187-.338.215-.71.072-1.072l-.003-.007-.003-.007c-.784-1.818-2.006-3.298-3.658-4.434C15.982 2.47 14.094 1.9 11.998 1.9c-1.695 0-3.261.385-4.688 1.16a10.536 10.536 0 0 0-2.715 2.096 1.364 1.364 0 0 0-.308-.453 1.38 1.38 0 0 0-.994-.403c-.38 0-.722.135-.992.406s-.403.614-.403.994v3c0 .38.135.724.406.995.27.27.614.405.994.405h3c.384 0 .727-.137.998-.412a1.38 1.38 0 0 0 .402-.993c0-.38-.135-.723-.406-.992ZM9.52 14.48a3.393 3.393 0 0 0 2.478 1.02c.965 0 1.8-.342 2.479-1.02a3.392 3.392 0 0 0 1.021-2.48c0-.963-.343-1.8-1.021-2.478A3.392 3.392 0 0 0 11.998 8.5c-.964 0-1.8.343-2.478 1.021A3.392 3.392 0 0 0 8.498 12c0 .964.344 1.8 1.022 2.479Z\"/></svg>') 12 12,auto}.unreal-container.pan{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.997 10.075a1.01 1.01 0 0 1-.738-.313 1.008 1.008 0 0 1-.312-.737V6.15l-.95.95a.998.998 0 0 1-.763.312 1.09 1.09 0 0 1-.763-.337 1.06 1.06 0 0 1-.324-.775c0-.3.108-.558.324-.775l2.776-2.775c.117-.116.237-.2.362-.25a1.04 1.04 0 0 1 .775 0c.125.05.246.134.363.25l2.8 2.8c.216.217.32.47.313.762a1.096 1.096 0 0 1-.338.763 1.058 1.058 0 0 1-.775.325c-.3 0-.558-.108-.775-.325l-.925-.925v2.875c0 .283-.104.53-.312.737a1.01 1.01 0 0 1-.738.313Zm0 11.5a1.04 1.04 0 0 1-.388-.075 1.103 1.103 0 0 1-.362-.25l-2.8-2.8a1.002 1.002 0 0 1-.313-.762c.009-.292.121-.546.337-.763.217-.217.475-.325.775-.325.3 0 .559.108.775.325l.926.925v-2.875c0-.283.104-.529.312-.737a1.01 1.01 0 0 1 .738-.313c.283 0 .529.104.738.313.208.208.312.454.312.737v2.875l.95-.95a.998.998 0 0 1 .762-.312c.292.008.546.12.763.337.216.217.324.475.324.775 0 .3-.108.559-.324.775l-2.775 2.775c-.117.116-.238.2-.363.25a1.04 1.04 0 0 1-.387.075Zm4.925-6.05a1.058 1.058 0 0 1-.326-.774c0-.3.109-.559.326-.776l.925-.925H14.97c-.283 0-.528-.104-.736-.312a1.01 1.01 0 0 1-.313-.738c0-.283.104-.53.313-.738.208-.208.453-.312.737-.312h2.875l-.95-.95a.998.998 0 0 1-.313-.762 1.09 1.09 0 0 1 .338-.764 1.06 1.06 0 0 1 .775-.324c.3 0 .558.108.775.324l2.774 2.776c.117.117.2.238.251.363a1.04 1.04 0 0 1 0 .775c-.05.124-.134.245-.25.362l-2.8 2.8c-.217.216-.471.32-.762.313a1.096 1.096 0 0 1-.763-.337Zm-11.4 0L2.746 12.75a1.103 1.103 0 0 1-.25-.362 1.04 1.04 0 0 1 0-.775c.05-.125.133-.246.25-.363l2.8-2.8c.216-.216.47-.32.762-.313.292.01.546.121.763.337.217.217.325.476.325.776 0 .3-.108.558-.325.775l-.925.925h2.875c.283 0 .529.104.737.312.208.209.313.455.313.738s-.105.53-.313.738a1.008 1.008 0 0 1-.737.312H6.147l.95.95c.217.217.32.471.312.762a1.09 1.09 0 0 1-.337.764 1.06 1.06 0 0 1-.775.324c-.3 0-.559-.108-.776-.324Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M9.22 7.912c.436.013.821-.15 1.13-.458l.097-.097v1.668c0 .422.16.793.458 1.09.298.299.67.46 1.092.46.422 0 .793-.161 1.091-.46.298-.297.459-.668.459-1.09V7.357l.071.072c.309.308.693.471 1.13.471.435 0 .82-.163 1.128-.471.301-.303.47-.676.483-1.102v-.001a1.501 1.501 0 0 0-.46-1.13l-2.799-2.8a1.6 1.6 0 0 0-.528-.36l-.003-.001a1.54 1.54 0 0 0-1.145 0l-.002.001a1.6 1.6 0 0 0-.529.36L8.118 5.172l-.001.001a1.56 1.56 0 0 0-.47 1.128c0 .435.163.82.47 1.128.303.303.676.472 1.103.484Zm0 0 .014-.5-.015.5Zm-1.311 6.865a1.497 1.497 0 0 0-.458-1.13l-.097-.097h1.668c.421 0 .793-.16 1.09-.458.298-.299.46-.67.46-1.092a1.51 1.51 0 0 0-.46-1.091 1.507 1.507 0 0 0-1.09-.459H7.354l.071-.072c.309-.308.472-.692.472-1.128 0-.436-.163-.82-.472-1.13a1.596 1.596 0 0 0-1.101-.482h-.002a1.501 1.501 0 0 0-1.129.459l-2.8 2.8a1.6 1.6 0 0 0-.36.528l-.001.003a1.54 1.54 0 0 0 0 1.144v.003c.081.2.208.375.362.529l2.774 2.775c.309.308.693.47 1.129.47.435 0 .82-.162 1.128-.47.303-.302.472-.676.484-1.102Zm0 0-.5-.014.5.015v-.001Zm3.038-8.627-.5.5.5.207V6.15Zm.475 15.814.002.001a1.54 1.54 0 0 0 1.145 0h.002c.2-.081.375-.208.53-.362l2.775-2.774a1.56 1.56 0 0 0 .47-1.129c0-.435-.162-.82-.47-1.128a1.589 1.589 0 0 0-1.103-.484 1.497 1.497 0 0 0-1.13.458l-.096.097v-1.668c0-.421-.161-.793-.459-1.09a1.509 1.509 0 0 0-1.091-.46c-.422 0-.794.161-1.092.46a1.507 1.507 0 0 0-.458 1.09v1.668l-.072-.072a1.558 1.558 0 0 0-1.129-.471c-.436 0-.82.163-1.128.471l-.001.001c-.301.302-.47.675-.483 1.101v.001c-.012.437.151.821.46 1.13l2.8 2.8c.153.153.328.28.528.36Zm5.146-6.085c.303.302.676.47 1.102.484a1.5 1.5 0 0 0 1.13-.46l2.8-2.8a1.6 1.6 0 0 0 .36-.528l.002-.003a1.54 1.54 0 0 0 0-1.144l-.001-.003a1.6 1.6 0 0 0-.361-.529l-2.774-2.775h-.001a1.56 1.56 0 0 0-1.128-.47c-.436 0-.82.162-1.128.47h-.001a1.59 1.59 0 0 0-.484 1.102c-.012.437.15.822.459 1.13l.097.097h-1.668c-.422 0-.793.16-1.09.459-.299.298-.46.67-.46 1.091 0 .422.161.793.46 1.092.297.297.668.458 1.09.458h1.668l-.072.072a1.558 1.558 0 0 0-.472 1.129c0 .435.164.82.472 1.128ZM6.147 13.05l.5.5.207-.5h-.707Z\"/></svg>') 12 12,auto}.unreal-container.dolly{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><mask id=\"a\" width=\"24\" height=\"24\" x=\"0\" y=\"0\" maskUnits=\"userSpaceOnUse\" style=\"mask-type:alpha\"><path fill=\"%23127392\" d=\"M0 0h24v24H0z\"/></mask><g mask=\"url(%23a)\"><path fill=\"%23000\" d=\"M12.002 20.575a1.026 1.026 0 0 1-.75-.325l-2.55-2.55a.933.933 0 0 1-.287-.713c.008-.275.113-.513.313-.713.2-.2.441-.3.725-.3.283 0 .524.1.724.3l.776.776V6.95l-.8.8c-.2.2-.438.296-.712.288a1.018 1.018 0 0 1-.713-.312c-.2-.2-.3-.442-.3-.726s.1-.525.3-.725l2.524-2.525a1.026 1.026 0 0 1 1.5 0l2.55 2.55c.2.2.296.438.289.713a1.023 1.023 0 0 1-.314.713c-.2.2-.441.3-.724.3a.988.988 0 0 1-.725-.3l-.775-.776v10.1l.8-.8c.2-.2.437-.296.712-.288.275.008.512.112.712.312.2.2.3.442.3.726s-.1.525-.3.725l-2.524 2.525a1.026 1.026 0 0 1-.75.325Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M13.553 8.153c.28.245.62.373 1 .373.415 0 .784-.153 1.078-.447.287-.287.446-.644.46-1.05v-.002a1.432 1.432 0 0 0-.435-1.08l-2.55-2.55-.354.353.354-.354a1.526 1.526 0 0 0-2.207 0L8.374 5.921A1.487 1.487 0 0 0 7.928 7c0 .416.152.785.446 1.08.288.287.645.446 1.052.457l4.127-.384Zm0 0v7.693m0-7.693a1.667 1.667 0 0 1-.079-.074l-3.021.075v7.693a1.482 1.482 0 0 0-1-.373c-.416 0-.785.153-1.079.447a1.522 1.522 0 0 0-.46 1.05v.002c-.011.417.14.786.435 1.08l2.55 2.55a1.527 1.527 0 0 0 2.207 0l2.525-2.524c.294-.294.446-.663.446-1.079 0-.416-.152-.785-.446-1.08a1.518 1.518 0 0 0-1.052-.457m0 0-.014.5.014-.5Zm0 0a1.424 1.424 0 0 0-1.027.383m0 0a1.583 1.583 0 0 0-.053.05l.354.354m-.3-.404v.104l.3.3m0 0-.3-.3v.6l.3-.3Z\"/></g></svg>%0A') 12 12,auto}.unreal-container.disabled:before{content:\"\";position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}#playerUI{position:absolute;z-index:10;width:100%}#statsContainer{display:none;text-align:left;background-color:#000c}#stats{padding:6px;font-weight:700;font-size:14px;color:#0f0}canvas{position:absolute;image-rendering:crisp-edges}#overlay{position:absolute;top:0;right:2%;z-index:100;padding:4px;border-top-width:0;-webkit-border-bottom-right-radius:5px;-moz-border-radius-bottomright:5px;border-bottom-right-radius:5px;-webkit-border-bottom-left-radius:5px;-moz-border-radius-bottomleft:5px;border-bottom-left-radius:5px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-touch-callout:none}.overlay{font-weight:lighter;font-family:var(--src-font-family-body, system-ui, sans-serif)}#overlayButton:hover{cursor:pointer}#overlayButton{font-size:40px;text-align:right}#overlaySettings{display:none;width:300px;padding:4px}#videoMessageOverlay{position:absolute;z-index:20;width:100%;margin:auto;font-size:1.8em;font-family:var(--src-font-family-body, system-ui, sans-serif)}#playButton{display:inline-block;height:auto}img#playButton{width:10%;max-width:241px}#UIInteraction{position:fixed}#UIInteractionButtonBoundary{padding:2px}#UIInteractionButton{cursor:pointer}#hiddenInput{position:absolute;left:-10%;width:0;opacity:0}#editTextButton{position:absolute;width:40px;height:40px}\n"], dependencies: [{ kind: "component", type: AfkTimeoutModalComponent, selector: "app-afk-timeout-modal", inputs: ["uiClasses", "contentTemplate"] }, { kind: "component", type: UnrealStatusComponent, selector: "app-unreal-status", inputs: ["uiClasses", "contentTemplate"] }, { kind: "component", type: FreezeFrameComponent, selector: "app-freeze-frame" }, { kind: "component", type: VideoStatsComponent, selector: "app-video-stats" }, { kind: "component", type: ResumeStreamButtonComponent, selector: "app-resume-stream-button", inputs: ["uiClasses", "contentTemplate"] }, { kind: "component", type: ImageLoadingSrcComponent, selector: "app-image-loading-src" }, { kind: "component", type: IntroSrcComponent, selector: "app-intro-src" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
8432
8988
|
}
|
|
8433
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8989
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealSceneComponent, decorators: [{
|
|
8434
8990
|
type: Component,
|
|
8435
8991
|
args: [{ selector: 'app-unreal-scene', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
8436
8992
|
AfkTimeoutModalComponent,
|
|
@@ -8500,5 +9056,5 @@ function provideUnrealModule() {
|
|
|
8500
9056
|
* Generated bundle index. Do not edit.
|
|
8501
9057
|
*/
|
|
8502
9058
|
|
|
8503
|
-
export { AFKService, AUTO_HIGH_RESOLUTION_IDLE_MS, AfkTimeoutModalComponent, AggregatorService, AnalyticsService, AnswerHandler, CommandTelemetryService, ConfigHandler, ConsoleExtensionsService, ControlScheme, DATA_CHANNEL_CONNECTION_TIMEOUT, DEBOUNCE_TO_MANY_RESIZE_CALLS, DEFAULT_AFK_TIMEOUT, DEFAULT_AFK_TIMEOUT_PERIOD, DESTROY_DISCONNECT_REASONS, DevModeService, DisconnectReason, FULL_HD_HEIGHT, FULL_HD_WIDTH, FileHandlerService, FileReceiverService, FpsMonitorService, FreezeFrameComponent, FreezeFrameService, INNER_RETRY_LIMIT, INSTANCE_READY_TIMEOUT, IceCandidateHandler, ImageLoadingSrcComponent, InputOptions, InputService, InstanceReadyHandler, InstanceReservedHandler, IntroSrcComponent, LatencyTimings, LoadingProgressService, MINIMAL_FPS, MIN_CONTAINER_SIZE, MessageType, MouseButton, MouseButtonsMask, OUTER_RETRY_DELAY, OnCloseHandler, OnErrorHandler, OnMessageHandler, OnOpenHandler, OrchestrationMessageTypes, POLLING_TIME, PlayerCountHandler, RECONNECT_CONFIG, REGION_PING_ACCURATE_SAMPLES, REGION_PING_BACKGROUND_REFRESH_DELAY_MS, REGION_PING_CACHE_KEY, REGION_PING_CACHE_TTL_MS, REGION_PING_WARMUP_DEADLINE_MS, RegionsPingService, SAME_SIZE_THRESHOLD, SCREEN_LOCKER_CONTAINER_ID, SIGNALLING_PERCENT_VALUE, SSInfoHandler, STREAMING_AUDIO_ID, STREAMING_VIDEO_ID, SafePipe, SignallingService, SpecialKeyCodes, StatGraphComponent, StreamAdoptionService, StreamStatusTelemetryService, StreamStatusTelemetryService2, SubService, ToClientMessage, UnrealAfkSlotDirective, UnrealCallbackService, UnrealCommunicatorService, UnrealEffects, UnrealResumeSlotDirective, UnrealSceneComponent, UnrealStatusMessage, UnrealStatusSlotDirective, VideoService, VideoStatsComponent, WSCloseCode_CIRRUS_ABNORMAL_CLOSURE, WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR, WSCloseCode_CIRRUS_PLAYER_DISCONNECTED, WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER, WSCloseCode_FORCE_CIRRUS_CLOSE, WSCloseCode_NORMAL_AFK_TIMEOUT, WSCloseCode_NORMAL_CLOSURE, WSCloseCode_NORMAL_MANUAL_DISCONNECT, WSCloseCode_UNKNOWN, WSCloseCodes, WS_OPEN_STATE, WS_RETRY_PER_INSTANCE, WS_TIMEOUT, WebRtcPlayerService, WebrtcErrorModalComponent, abortEstablishingConnection, answerSent, changeStatusMainVideoOnScene, changeStreamResolutionAction, commandCompleted, commandStarted, dataChannelConnected, dataChannelReady, decodeData, destroyRemoteConnections, destroyUnrealScene, disconnectStream, dispatchResize, dropConnection, dropDC, dropPC, floatToPercents, floatToSmoothPercents, forceResizeViewport, fromResizeObserver, getActiveUrl, getImageFromVideoStream, getResizeStudioValues, getResizeValuesUniversal, getRtcErrorMessage, iceConnectionFailed, initSignalling, instanceReady, isAppOwned, isMetaboxMode, keepMaxUntilReset, makeEven, pollingEnded, pollingStarted, provideUnrealModule, provideUnrealState, qpToQuality, reconnectPeer, reconnectPeerFailed, reconnectPeerSuccess, regionPingFetchEnd, regionPingFetchStart, regionResolved, resetAfk, resetConfig, resetDataChannelForReconnect, resetIntroSrc, resetUserInactivityTimeout, resetWarnTimeout, resolveSkin, saveAnalyticsEvent, selectCirrusConnectionId, selectClientAndViewIds, selectCommandProgress, selectFreezeFrameCombinedDataUrl, selectFreezeFrameDataUrl, selectFreezeFrameDataUrlFromVideo, selectFreezeFrameProgressMessageFromVideo, selectIsAutostart, selectIsExistMatchUrls, selectIsFreezeFrameLoading, selectIsFullyConnected, selectIsLoaderScreenVisible, selectIsVideoPlayingAndDataChannelConnected, selectShowLoader, selectShowReconnectPopup, selectSignalingParameters, selectStreamConfig, selectTotalProgress, selectUserInactivityDetected, selectWarnTimeout, setAfkTimerCountdown, setAfkTimerHide, setAfkTimerVisible, setAwsInstance, setCirrusConnected, setCirrusDisconnected, setConfig, setEstablishingConnection, setFreezeFrame, setFreezeFrameFromVideo, setIntroImageSrc, setIntroVideoSrc, setLoadingImageSrc, setLoopBackCommandIsCompleted, setMaxFps, setOrchestrationContext, setOrchestrationMessage, setOrchestrationParameters, setOrchestrationProgress, setSignalingName, setStatusMessage, setStatusPercentSignallingServer, setStreamClientCompanyId, setStreamViewId, setUnrealPlaywrightConfig, setUserInactivityTimeout, setViewportNotReady, setViewportReady, showLoadingProgress, showResumeStreamPopup, showUnrealErrorMessage, showUserInactivityTimeoutPopup, signalingRetryAttempted, startStream, streamAdopted, trackMixpanelEvent, trackTelemetryData, uint8ToBase64, unrealCommandCallback, unrealFeature, unrealReducer, updateCirrusInfo, videoAdaptedToContainer, videoStreamInitialized };
|
|
9059
|
+
export { AFKService, AUTO_HIGH_RESOLUTION_IDLE_MS, AfkTimeoutModalComponent, AggregatorService, AnalyticsService, AnswerHandler, CommandTelemetryService, ConfigHandler, ConsoleExtensionsService, ControlScheme, DATA_CHANNEL_CONNECTION_TIMEOUT, DEBOUNCE_TO_MANY_RESIZE_CALLS, DEFAULT_AFK_TIMEOUT, DEFAULT_AFK_TIMEOUT_PERIOD, DESTROY_DISCONNECT_REASONS, DevModeService, DisconnectReason, FULL_HD_HEIGHT, FULL_HD_WIDTH, FileHandlerService, FileReceiverService, FpsMonitorService, FreezeFrameComponent, FreezeFrameService, IME_PROCESS_KEY, INNER_RETRY_LIMIT, INSTANCE_READY_TIMEOUT, IceCandidateHandler, ImageLoadingSrcComponent, InputOptions, InputService, InstanceReadyHandler, InstanceReservedHandler, IntroSrcComponent, InvertedKeyMap, KeyboardNumericCode, LatencyTimings, LoadingProgressService, MINIMAL_FPS, MIN_CONTAINER_SIZE, MODIFIER_KEY_CODES, MessageType, MouseButton, MouseButtonsMask, OUTER_RETRY_DELAY, OnCloseHandler, OnErrorHandler, OnMessageHandler, OnOpenHandler, OrchestrationMessageTypes, POLLING_TIME, PlayerCountHandler, RECONNECT_CONFIG, REGION_PING_ACCURATE_SAMPLES, REGION_PING_BACKGROUND_REFRESH_DELAY_MS, REGION_PING_CACHE_KEY, REGION_PING_CACHE_TTL_MS, REGION_PING_WARMUP_DEADLINE_MS, RegionsPingService, SAME_SIZE_THRESHOLD, SCREEN_LOCKER_CONTAINER_ID, SIGNALLING_PERCENT_VALUE, SSInfoHandler, STREAMING_AUDIO_ID, STREAMING_VIDEO_ID, SafePipe, SignallingService, SpecialKeyCodes, StatGraphComponent, StreamAdoptionService, StreamStatusTelemetryService, StreamStatusTelemetryService2, SubService, ToClientMessage, UnrealAfkSlotDirective, UnrealCallbackService, UnrealCommunicatorService, UnrealEffects, UnrealResumeSlotDirective, UnrealSceneComponent, UnrealStatusMessage, UnrealStatusSlotDirective, VideoService, VideoStatsComponent, WSCloseCode_CIRRUS_ABNORMAL_CLOSURE, WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR, WSCloseCode_CIRRUS_PLAYER_DISCONNECTED, WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER, WSCloseCode_FORCE_CIRRUS_CLOSE, WSCloseCode_NORMAL_AFK_TIMEOUT, WSCloseCode_NORMAL_CLOSURE, WSCloseCode_NORMAL_MANUAL_DISCONNECT, WSCloseCode_UNKNOWN, WSCloseCodes, WS_OPEN_STATE, WS_RETRY_PER_INSTANCE, WS_TIMEOUT, WebRtcPlayerService, WebrtcErrorModalComponent, abortEstablishingConnection, answerSent, changeStatusMainVideoOnScene, changeStreamResolutionAction, commandCompleted, commandStarted, dataChannelConnected, dataChannelReady, decodeData, destroyRemoteConnections, destroyUnrealScene, disconnectStream, dispatchResize, dropConnection, dropDC, dropPC, floatToPercents, floatToSmoothPercents, forceResizeViewport, fromResizeObserver, getActiveUrl, getImageFromVideoStream, getResizeStudioValues, getResizeValuesUniversal, getRtcErrorMessage, iceConnectionFailed, initSignalling, instanceReady, isAppOwned, isMetaboxMode, keepMaxUntilReset, makeEven, pollingEnded, pollingStarted, provideUnrealModule, provideUnrealState, qpToQuality, reconnectPeer, reconnectPeerFailed, reconnectPeerSuccess, regionPingFetchEnd, regionPingFetchStart, regionResolved, resetAfk, resetConfig, resetDataChannelForReconnect, resetIntroSrc, resetUserInactivityTimeout, resetWarnTimeout, resolveSkin, saveAnalyticsEvent, selectCirrusConnectionId, selectClientAndViewIds, selectCommandProgress, selectFreezeFrameCombinedDataUrl, selectFreezeFrameDataUrl, selectFreezeFrameDataUrlFromVideo, selectFreezeFrameProgressMessageFromVideo, selectIsAutostart, selectIsExistMatchUrls, selectIsFreezeFrameLoading, selectIsFullyConnected, selectIsLoaderScreenVisible, selectIsVideoPlayingAndDataChannelConnected, selectShowLoader, selectShowReconnectPopup, selectSignalingParameters, selectStreamConfig, selectTotalProgress, selectUserInactivityDetected, selectWarnTimeout, setAfkTimerCountdown, setAfkTimerHide, setAfkTimerVisible, setAwsInstance, setCirrusConnected, setCirrusDisconnected, setConfig, setEstablishingConnection, setFreezeFrame, setFreezeFrameFromVideo, setIntroImageSrc, setIntroVideoSrc, setLoadingImageSrc, setLoopBackCommandIsCompleted, setMaxFps, setOrchestrationContext, setOrchestrationMessage, setOrchestrationParameters, setOrchestrationProgress, setSignalingName, setStatusMessage, setStatusPercentSignallingServer, setStreamClientCompanyId, setStreamViewId, setUnrealPlaywrightConfig, setUserInactivityTimeout, setViewportNotReady, setViewportReady, showLoadingProgress, showResumeStreamPopup, showUnrealErrorMessage, showUserInactivityTimeoutPopup, signalingRetryAttempted, startStream, streamAdopted, trackMixpanelEvent, trackTelemetryData, uint8ToBase64, unrealCommandCallback, unrealFeature, unrealReducer, updateCirrusInfo, videoAdaptedToContainer, videoStreamInitialized };
|
|
8504
9060
|
//# sourceMappingURL=3dsource-angular-unreal-module.mjs.map
|