@3dsource/angular-unreal-module 0.0.177 → 0.0.181
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,157 @@ 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 is deliberately absent. A numpad key reports the same `code` in
|
|
320
|
+
* both NumLock states but a different virtual key — `Numpad4` is 37/`VK_LEFT`
|
|
321
|
+
* with NumLock off and 100/`VK_NUMPAD4` with it on — so any entry here would
|
|
322
|
+
* have to commit to one state and be wrong in the other. Falling through to
|
|
323
|
+
* `event.keyCode` is right in both. `NumpadAdd`/`Subtract`/`Multiply`/`Divide`
|
|
324
|
+
* stay because they do not change with NumLock.
|
|
325
|
+
*
|
|
326
|
+
* `SpecialKeyCodes` in `./buttons-codes` repeats seven of these entries with
|
|
327
|
+
* the same values. The two are kept apart because both are public API; merging
|
|
328
|
+
* them would be a breaking change.
|
|
329
|
+
*
|
|
330
|
+
* Values must stay unique so `InvertedKeyMap` is lossless. The `OSLeft`/
|
|
331
|
+
* `MetaLeft` and `OSRight`/`MetaRight` pairs share a value on purpose: they are
|
|
332
|
+
* legacy and current names for the same physical key.
|
|
333
|
+
*/
|
|
334
|
+
const KeyboardNumericCode = {
|
|
335
|
+
Backspace: 8,
|
|
336
|
+
Tab: 9,
|
|
337
|
+
Enter: 13,
|
|
338
|
+
ShiftLeft: 16,
|
|
339
|
+
ControlLeft: 17,
|
|
340
|
+
AltLeft: 18,
|
|
341
|
+
Escape: 27,
|
|
342
|
+
Space: 32,
|
|
343
|
+
ArrowLeft: 37,
|
|
344
|
+
ArrowUp: 38,
|
|
345
|
+
ArrowRight: 39,
|
|
346
|
+
ArrowDown: 40,
|
|
347
|
+
Digit0: 48,
|
|
348
|
+
Digit1: 49,
|
|
349
|
+
Digit2: 50,
|
|
350
|
+
Digit3: 51,
|
|
351
|
+
Digit4: 52,
|
|
352
|
+
Digit5: 53,
|
|
353
|
+
Digit6: 54,
|
|
354
|
+
Digit7: 55,
|
|
355
|
+
Digit8: 56,
|
|
356
|
+
Digit9: 57,
|
|
357
|
+
KeyA: 65,
|
|
358
|
+
KeyB: 66,
|
|
359
|
+
KeyC: 67,
|
|
360
|
+
KeyD: 68,
|
|
361
|
+
KeyE: 69,
|
|
362
|
+
KeyF: 70,
|
|
363
|
+
KeyG: 71,
|
|
364
|
+
KeyH: 72,
|
|
365
|
+
KeyI: 73,
|
|
366
|
+
KeyJ: 74,
|
|
367
|
+
KeyK: 75,
|
|
368
|
+
KeyL: 76,
|
|
369
|
+
KeyM: 77,
|
|
370
|
+
KeyN: 78,
|
|
371
|
+
KeyO: 79,
|
|
372
|
+
KeyP: 80,
|
|
373
|
+
KeyQ: 81,
|
|
374
|
+
KeyR: 82,
|
|
375
|
+
KeyS: 83,
|
|
376
|
+
KeyT: 84,
|
|
377
|
+
KeyU: 85,
|
|
378
|
+
KeyV: 86,
|
|
379
|
+
KeyW: 87,
|
|
380
|
+
KeyX: 88,
|
|
381
|
+
KeyY: 89,
|
|
382
|
+
KeyZ: 90,
|
|
383
|
+
// Chrome/Safari report 91 for the left Cmd/Win key, Firefox on macOS 224.
|
|
384
|
+
// The right one shares keyCode 93 with ContextMenu on Chrome/Safari, making
|
|
385
|
+
// the two indistinguishable. Unreal numbers them 91 and 92.
|
|
386
|
+
OSLeft: 91,
|
|
387
|
+
MetaLeft: 91,
|
|
388
|
+
OSRight: 92,
|
|
389
|
+
MetaRight: 92,
|
|
390
|
+
ContextMenu: 93,
|
|
391
|
+
NumpadMultiply: 106,
|
|
392
|
+
NumpadAdd: 107,
|
|
393
|
+
NumpadSubtract: 109,
|
|
394
|
+
NumpadDivide: 111,
|
|
395
|
+
F1: 112,
|
|
396
|
+
F2: 113,
|
|
397
|
+
F3: 114,
|
|
398
|
+
F4: 115,
|
|
399
|
+
F5: 116,
|
|
400
|
+
F6: 117,
|
|
401
|
+
F7: 118,
|
|
402
|
+
F8: 119,
|
|
403
|
+
F9: 120,
|
|
404
|
+
F10: 121,
|
|
405
|
+
F11: 122,
|
|
406
|
+
F12: 123,
|
|
407
|
+
NumLock: 144,
|
|
408
|
+
ScrollLock: 145,
|
|
409
|
+
Semicolon: 186,
|
|
410
|
+
Equal: 187,
|
|
411
|
+
Comma: 188,
|
|
412
|
+
Minus: 189,
|
|
413
|
+
Period: 190,
|
|
414
|
+
Slash: 191,
|
|
415
|
+
Backquote: 192,
|
|
416
|
+
BracketLeft: 219,
|
|
417
|
+
Backslash: 220,
|
|
418
|
+
BracketRight: 221,
|
|
419
|
+
Quote: 222,
|
|
420
|
+
IntlBackslash: 226,
|
|
421
|
+
// Unreal keeps distinct codes for the right-hand modifiers; the DOM reports
|
|
422
|
+
// both sides of each pair under the same `keyCode`.
|
|
423
|
+
ShiftRight: 253,
|
|
424
|
+
ControlRight: 254,
|
|
425
|
+
AltRight: 255,
|
|
426
|
+
};
|
|
427
|
+
/**
|
|
428
|
+
* The `keyCode` a browser reports while an IME is composing (`VK_PROCESSKEY`).
|
|
429
|
+
*
|
|
430
|
+
* `event.code` keeps naming the *physical* key during composition — `KeyW`,
|
|
431
|
+
* `KeyA` and friends — so a consumer that forwards keys has to drop these
|
|
432
|
+
* events explicitly or typing CJK text turns into keystrokes.
|
|
433
|
+
*/
|
|
434
|
+
const IME_PROCESS_KEY = 229;
|
|
435
|
+
/**
|
|
436
|
+
* Codes of the keys that are themselves modifiers. A modifier's own `keydown`
|
|
437
|
+
* already reports `ctrlKey`/`metaKey` as pressed, so a "browser shortcut in
|
|
438
|
+
* flight" check has to exempt them or `ControlRight` would block itself.
|
|
439
|
+
*/
|
|
440
|
+
const MODIFIER_KEY_CODES = new Set([
|
|
441
|
+
'ShiftLeft',
|
|
442
|
+
'ShiftRight',
|
|
443
|
+
'ControlLeft',
|
|
444
|
+
'ControlRight',
|
|
445
|
+
'AltLeft',
|
|
446
|
+
'AltRight',
|
|
447
|
+
'MetaLeft',
|
|
448
|
+
'MetaRight',
|
|
449
|
+
'OSLeft',
|
|
450
|
+
'OSRight',
|
|
451
|
+
]);
|
|
452
|
+
const InvertedKeyMapValues = {};
|
|
453
|
+
//For use for InvertedKeyMap[32] will return 'Space' and so on
|
|
454
|
+
const InvertedKeyMap = InvertedKeyMapValues;
|
|
455
|
+
Object.entries(KeyboardNumericCode).forEach(
|
|
456
|
+
// @ts-expect-error @typescript-eslint/ban-ts-comment
|
|
457
|
+
([key, value]) => {
|
|
458
|
+
InvertedKeyMapValues[value] = key;
|
|
459
|
+
});
|
|
460
|
+
|
|
310
461
|
const ControlScheme = {
|
|
311
462
|
// A mouse can lock inside the WebRTC player, so the user can simply move the
|
|
312
463
|
// mouse to control the orientation of the camera. The user presses the
|
|
@@ -491,8 +642,12 @@ const UnrealStatusMessage = {
|
|
|
491
642
|
};
|
|
492
643
|
|
|
493
644
|
const COMMAND_EXILE_TIMEOUT_MS = 10_000;
|
|
645
|
+
const normalizeId = (value) => String(value).trim().replace(/ +/gi, '_').toLowerCase();
|
|
494
646
|
function exileExpiredCommands(commandsInProgress, idToRemove, now) {
|
|
495
|
-
|
|
647
|
+
// Case-insensitive, like the `whereNot()` predicate this replaces: a caller
|
|
648
|
+
// supplies `correlationId`, and it round-trips through the engine.
|
|
649
|
+
const idKey = normalizeId(idToRemove);
|
|
650
|
+
let remaining = commandsInProgress.filter(({ id }) => normalizeId(id) !== idKey);
|
|
496
651
|
const expired = remaining.filter(({ timeStamp }) => now - timeStamp > COMMAND_EXILE_TIMEOUT_MS);
|
|
497
652
|
if (expired.length) {
|
|
498
653
|
const expiredIds = new Set(expired.map(({ id }) => id));
|
|
@@ -825,6 +980,488 @@ const unrealFeature = createFeature({
|
|
|
825
980
|
reducer: unrealReducer,
|
|
826
981
|
});
|
|
827
982
|
|
|
983
|
+
function fitIntoRectangle(objectRect, areaRect, round = true, fixedRatio = null) {
|
|
984
|
+
const result = { x: 0, y: 0, w: 0, h: 0, scale: 1 };
|
|
985
|
+
const ratio = objectRect.h / objectRect.w;
|
|
986
|
+
if (objectRect.h > objectRect.w) {
|
|
987
|
+
result.h = areaRect.h;
|
|
988
|
+
result.w = areaRect.h / ratio;
|
|
989
|
+
if (result.w > areaRect.w) {
|
|
990
|
+
result.w = areaRect.w;
|
|
991
|
+
result.h = areaRect.w * ratio;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
else {
|
|
995
|
+
result.w = areaRect.w;
|
|
996
|
+
result.h = areaRect.w * ratio;
|
|
997
|
+
if (result.h > areaRect.h) {
|
|
998
|
+
result.h = areaRect.h;
|
|
999
|
+
result.w = areaRect.h / ratio;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
if (fixedRatio) {
|
|
1003
|
+
result.w = objectRect.w * fixedRatio;
|
|
1004
|
+
result.h = objectRect.h * fixedRatio;
|
|
1005
|
+
}
|
|
1006
|
+
const wOut = round ? Math.floor(result.w) : result.w;
|
|
1007
|
+
const hOut = round ? Math.floor(result.h) : result.h;
|
|
1008
|
+
return {
|
|
1009
|
+
x: areaRect.x + (areaRect.w - wOut) / 2,
|
|
1010
|
+
y: areaRect.y + (areaRect.h - hOut) / 2,
|
|
1011
|
+
w: wOut,
|
|
1012
|
+
h: hOut,
|
|
1013
|
+
scale: wOut / objectRect.w,
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
const canvasCacheObj = {};
|
|
1018
|
+
function getCanvasCached(id) {
|
|
1019
|
+
if (!canvasCacheObj[id]) {
|
|
1020
|
+
const canvas = document.createElement('canvas');
|
|
1021
|
+
const ctx = canvas.getContext('2d');
|
|
1022
|
+
if (!ctx) {
|
|
1023
|
+
throw new Error('Canvas 2D context is unavailable.');
|
|
1024
|
+
}
|
|
1025
|
+
canvasCacheObj[id] = {
|
|
1026
|
+
canvas,
|
|
1027
|
+
ctx,
|
|
1028
|
+
};
|
|
1029
|
+
}
|
|
1030
|
+
return canvasCacheObj[id];
|
|
1031
|
+
}
|
|
1032
|
+
function sourceDimensions(imageElement) {
|
|
1033
|
+
const naturalWidth = 'naturalWidth' in imageElement ? imageElement.naturalWidth : 0;
|
|
1034
|
+
const naturalHeight = 'naturalHeight' in imageElement ? imageElement.naturalHeight : 0;
|
|
1035
|
+
return {
|
|
1036
|
+
width: naturalWidth || imageElement.width,
|
|
1037
|
+
height: naturalHeight || imageElement.height,
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
function canvasContext(canvas) {
|
|
1041
|
+
const context = canvas.getContext('2d');
|
|
1042
|
+
if (!context) {
|
|
1043
|
+
throw new Error('Canvas 2D context is unavailable.');
|
|
1044
|
+
}
|
|
1045
|
+
return context;
|
|
1046
|
+
}
|
|
1047
|
+
function getSnapshot2(imageElement, maxWidth = 1024, output = 'image/png', quality = 0.9) {
|
|
1048
|
+
const canvasHelper = document.createElement('canvas');
|
|
1049
|
+
const drawCTX = canvasContext(canvasHelper);
|
|
1050
|
+
const dimensions = sourceDimensions(imageElement);
|
|
1051
|
+
const prop = fitIntoRectangle({
|
|
1052
|
+
x: 0,
|
|
1053
|
+
y: 0,
|
|
1054
|
+
w: dimensions.width,
|
|
1055
|
+
h: dimensions.height,
|
|
1056
|
+
}, {
|
|
1057
|
+
x: 0,
|
|
1058
|
+
y: 0,
|
|
1059
|
+
w: maxWidth,
|
|
1060
|
+
h: dimensions.height,
|
|
1061
|
+
});
|
|
1062
|
+
const width = prop.w;
|
|
1063
|
+
const height = prop.h;
|
|
1064
|
+
canvasHelper.width = width;
|
|
1065
|
+
canvasHelper.height = height;
|
|
1066
|
+
drawCTX.save();
|
|
1067
|
+
drawCTX.clearRect(0, 0, width, height);
|
|
1068
|
+
drawCTX.drawImage(imageElement, 0, 0, width, height);
|
|
1069
|
+
drawCTX.restore();
|
|
1070
|
+
if (output === 'canvas') {
|
|
1071
|
+
return canvasHelper;
|
|
1072
|
+
}
|
|
1073
|
+
return canvasHelper.toDataURL(output, quality);
|
|
1074
|
+
}
|
|
1075
|
+
function getSnapshot(imageElement, maxWidth = 1024, output = 'image/png', quality = 0.9) {
|
|
1076
|
+
const canvasHelper = document.createElement('canvas');
|
|
1077
|
+
const drawCTX = canvasContext(canvasHelper);
|
|
1078
|
+
const dimensions = sourceDimensions(imageElement);
|
|
1079
|
+
const prop = fitIntoRectangle({
|
|
1080
|
+
x: 0,
|
|
1081
|
+
y: 0,
|
|
1082
|
+
w: dimensions.width,
|
|
1083
|
+
h: dimensions.height,
|
|
1084
|
+
}, {
|
|
1085
|
+
x: 0,
|
|
1086
|
+
y: 0,
|
|
1087
|
+
w: dimensions.width / 2,
|
|
1088
|
+
h: dimensions.height,
|
|
1089
|
+
});
|
|
1090
|
+
const width = prop.w;
|
|
1091
|
+
const height = prop.h;
|
|
1092
|
+
canvasHelper.width = width;
|
|
1093
|
+
canvasHelper.height = height;
|
|
1094
|
+
drawCTX.save();
|
|
1095
|
+
drawCTX.clearRect(0, 0, width, height);
|
|
1096
|
+
drawCTX.drawImage(imageElement, 0, 0, width, height);
|
|
1097
|
+
drawCTX.restore();
|
|
1098
|
+
if (width > maxWidth * 2) {
|
|
1099
|
+
return getSnapshot(canvasHelper, maxWidth, output, quality);
|
|
1100
|
+
}
|
|
1101
|
+
return getSnapshot2(imageElement, maxWidth, output, quality);
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
/* eslint-disable prefer-const */
|
|
1105
|
+
/**
|
|
1106
|
+
* Colour-space conversions used by the dev stat graph overlay.
|
|
1107
|
+
*
|
|
1108
|
+
* Carried over verbatim; `HSVtoRGB` reassigns its locals, hence the
|
|
1109
|
+
* file-level `prefer-const` exemption.
|
|
1110
|
+
*/
|
|
1111
|
+
function HEXtoRGB(color) {
|
|
1112
|
+
if (typeof color === 'string') {
|
|
1113
|
+
color = parseInt(color.replace('#', ''), 16);
|
|
1114
|
+
}
|
|
1115
|
+
const r = (color >> 16) & 255;
|
|
1116
|
+
const g = (color >> 8) & 255;
|
|
1117
|
+
const b = color & 255;
|
|
1118
|
+
return { r: r, g: g, b: b };
|
|
1119
|
+
}
|
|
1120
|
+
function RGBtoHEX(r, g, b) {
|
|
1121
|
+
let redColor = r.toString(16);
|
|
1122
|
+
let greenColor = g.toString(16);
|
|
1123
|
+
let blackColor = b.toString(16);
|
|
1124
|
+
if (redColor.length === 1) {
|
|
1125
|
+
redColor = '0' + redColor;
|
|
1126
|
+
}
|
|
1127
|
+
if (greenColor.length === 1) {
|
|
1128
|
+
greenColor = '0' + greenColor;
|
|
1129
|
+
}
|
|
1130
|
+
if (blackColor.length === 1) {
|
|
1131
|
+
blackColor = '0' + blackColor;
|
|
1132
|
+
}
|
|
1133
|
+
return (redColor + greenColor + blackColor).toUpperCase();
|
|
1134
|
+
}
|
|
1135
|
+
/**
|
|
1136
|
+
* RGB from the respective figures, HSV sequences in terms of returns.
|
|
1137
|
+
* RGB values are as follows.
|
|
1138
|
+
* R - a number from 0 to 255
|
|
1139
|
+
* G - a number from 0 to 255
|
|
1140
|
+
* B - a number from 0 to 255
|
|
1141
|
+
*
|
|
1142
|
+
* HSV values are as follows.
|
|
1143
|
+
* H - a number between 360-0
|
|
1144
|
+
* S - number between 0 and 1.0
|
|
1145
|
+
* V - number between 0 and 1.0
|
|
1146
|
+
*
|
|
1147
|
+
* Cannot compute, including alpha.
|
|
1148
|
+
* @ Param r the red (R) indicating the number (0x00 to 0xFF to)
|
|
1149
|
+
* @ Param g green (G) indicates the number (0x00 to 0xFF to)
|
|
1150
|
+
* @ Param b blue (B) shows the number (0x00 to 0xFF to)
|
|
1151
|
+
* @ Return HSV values as [H, S, V]
|
|
1152
|
+
**/
|
|
1153
|
+
function RGBtoHSV(r, g, b) {
|
|
1154
|
+
r /= 255;
|
|
1155
|
+
g /= 255;
|
|
1156
|
+
b /= 255;
|
|
1157
|
+
let h = 0;
|
|
1158
|
+
let s;
|
|
1159
|
+
let x, y;
|
|
1160
|
+
if (r >= g)
|
|
1161
|
+
x = r;
|
|
1162
|
+
else
|
|
1163
|
+
x = g;
|
|
1164
|
+
if (b > x)
|
|
1165
|
+
x = b;
|
|
1166
|
+
if (r <= g)
|
|
1167
|
+
y = r;
|
|
1168
|
+
else
|
|
1169
|
+
y = g;
|
|
1170
|
+
if (b < y)
|
|
1171
|
+
y = b;
|
|
1172
|
+
const v = x;
|
|
1173
|
+
const c = x - y;
|
|
1174
|
+
if (x === 0)
|
|
1175
|
+
s = 0;
|
|
1176
|
+
else
|
|
1177
|
+
s = c / x;
|
|
1178
|
+
if (s !== 0) {
|
|
1179
|
+
if (r === x) {
|
|
1180
|
+
h = (g - b) / c;
|
|
1181
|
+
}
|
|
1182
|
+
else {
|
|
1183
|
+
if (g === x) {
|
|
1184
|
+
h = 2 + (b - r) / c;
|
|
1185
|
+
}
|
|
1186
|
+
else {
|
|
1187
|
+
if (b === x) {
|
|
1188
|
+
h = 4 + (r - g) / c;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
h = h * 60;
|
|
1193
|
+
if (h < 0)
|
|
1194
|
+
h = h + 360;
|
|
1195
|
+
}
|
|
1196
|
+
return [h, s, v];
|
|
1197
|
+
}
|
|
1198
|
+
/**
|
|
1199
|
+
* HSV from each of the RGB values to determine a return as a number[].
|
|
1200
|
+
* RGB values are as follows.
|
|
1201
|
+
* R - a number from 0 to 255
|
|
1202
|
+
* G - a number from 0 to 255
|
|
1203
|
+
* B - a number from 0 to 255
|
|
1204
|
+
*
|
|
1205
|
+
* HSV values are as follows.
|
|
1206
|
+
* H - a number between 360-0
|
|
1207
|
+
* S - number between 0 and 1.0
|
|
1208
|
+
* V - number between 0 and 1.0
|
|
1209
|
+
*
|
|
1210
|
+
* H is replaced with equivalent numbers in the range of the 360-0 that is out of range.
|
|
1211
|
+
* Cannot compute, including alpha.
|
|
1212
|
+
*
|
|
1213
|
+
* @ Param h hue (Hue) number that indicates (to 360-0)
|
|
1214
|
+
* @ Param s the saturation (Saturation) shows the number (0.0 to 1.0)
|
|
1215
|
+
* @ Param v lightness (Value) indicates the number (0.0 to 1.0)
|
|
1216
|
+
* @ Return RGB values into a number[] of [R, G, B]
|
|
1217
|
+
**/
|
|
1218
|
+
function HSVtoRGB(h, s, v) {
|
|
1219
|
+
let r = 0, g = 0, b = 0;
|
|
1220
|
+
let i, x, y, z;
|
|
1221
|
+
if (s < 0) {
|
|
1222
|
+
s = 0;
|
|
1223
|
+
}
|
|
1224
|
+
if (s > 1) {
|
|
1225
|
+
s = 1;
|
|
1226
|
+
}
|
|
1227
|
+
if (v < 0) {
|
|
1228
|
+
v = 0;
|
|
1229
|
+
}
|
|
1230
|
+
if (v > 1) {
|
|
1231
|
+
v = 1;
|
|
1232
|
+
}
|
|
1233
|
+
h = h % 360;
|
|
1234
|
+
if (h < 0) {
|
|
1235
|
+
h += 360;
|
|
1236
|
+
}
|
|
1237
|
+
h /= 60;
|
|
1238
|
+
i = h >> 0;
|
|
1239
|
+
x = v * (1 - s);
|
|
1240
|
+
y = v * (1 - s * (h - i));
|
|
1241
|
+
z = v * (1 - s * (1 - h + i));
|
|
1242
|
+
switch (i) {
|
|
1243
|
+
case 0:
|
|
1244
|
+
r = v;
|
|
1245
|
+
g = z;
|
|
1246
|
+
b = x;
|
|
1247
|
+
break;
|
|
1248
|
+
case 1:
|
|
1249
|
+
r = y;
|
|
1250
|
+
g = v;
|
|
1251
|
+
b = x;
|
|
1252
|
+
break;
|
|
1253
|
+
case 2:
|
|
1254
|
+
r = x;
|
|
1255
|
+
g = v;
|
|
1256
|
+
b = z;
|
|
1257
|
+
break;
|
|
1258
|
+
case 3:
|
|
1259
|
+
r = x;
|
|
1260
|
+
g = y;
|
|
1261
|
+
b = v;
|
|
1262
|
+
break;
|
|
1263
|
+
case 4:
|
|
1264
|
+
r = z;
|
|
1265
|
+
g = x;
|
|
1266
|
+
b = v;
|
|
1267
|
+
break;
|
|
1268
|
+
case 5:
|
|
1269
|
+
r = v;
|
|
1270
|
+
g = x;
|
|
1271
|
+
b = y;
|
|
1272
|
+
break;
|
|
1273
|
+
}
|
|
1274
|
+
return [(r * 255) >> 0, (g * 255) >> 0, (b * 255) >> 0];
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
/** Console palette for the Unreal/Cirrus message log. */
|
|
1278
|
+
const COLOR_CODES = {
|
|
1279
|
+
TO_UNREAL: ['#ffffff', '#005912', `UNREAL <-`],
|
|
1280
|
+
TAP_LOG: ['#ffff00', '#1976d2', ' [TAPLOG]'],
|
|
1281
|
+
FROM_UNREAL: ['#ffff00', '#898989', 'UNREAL ->'],
|
|
1282
|
+
FROM_UNREAL_ERROR: ['#ffffff', '#ff0000', 'UNREAL ERROR ->'],
|
|
1283
|
+
FROM_CIRRUS: ['#ffffff', '#ef702b', 'CIRRUS ->'],
|
|
1284
|
+
FROM_CIRRUS_ERROR: ['#ffffff', '#ff0000', 'CIRRUS ->'],
|
|
1285
|
+
TO_CIRRUS: ['#ffffff', '#3c9738', 'CIRRUS <-'],
|
|
1286
|
+
};
|
|
1287
|
+
|
|
1288
|
+
function generateUuid() {
|
|
1289
|
+
return v4();
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
/**
|
|
1293
|
+
* Truthiness with the string forms folded in: `'false'`, `'undefined'` and
|
|
1294
|
+
* `'null'` are falsy here, which `Boolean` would call true.
|
|
1295
|
+
*/
|
|
1296
|
+
const Truthy = (value) => !!value && value !== 'false' && value !== 'undefined' && value !== 'null';
|
|
1297
|
+
/** The inverse of {@link Truthy}. */
|
|
1298
|
+
const Falsy = (value) => !Truthy(value);
|
|
1299
|
+
|
|
1300
|
+
/* eslint-disable no-console -- this file *is* the console wrapper; every call
|
|
1301
|
+
is gated behind `Logger.isDevMode`. */
|
|
1302
|
+
/**
|
|
1303
|
+
* Left-pads `input` to `size`, then trims to the last `size` characters — a
|
|
1304
|
+
* value longer than `size` is truncated, not left as-is.
|
|
1305
|
+
*/
|
|
1306
|
+
function pad(input, size, symbol = '0') {
|
|
1307
|
+
let s = input + '';
|
|
1308
|
+
while (s.length < size) {
|
|
1309
|
+
s = symbol + s;
|
|
1310
|
+
}
|
|
1311
|
+
return s.slice(-size);
|
|
1312
|
+
}
|
|
1313
|
+
/** `UTC:HH:MM:SS.mmm` for the current instant. */
|
|
1314
|
+
function timeUTCToString() {
|
|
1315
|
+
const date = new Date();
|
|
1316
|
+
return `UTC:${pad(date.getUTCHours(), 2)}:${pad(date.getUTCMinutes(), 2)}:${pad(date.getUTCSeconds(), 2)}.${pad(date.getUTCMilliseconds(), 3)}`;
|
|
1317
|
+
}
|
|
1318
|
+
class Logger {
|
|
1319
|
+
// Guard the top-level `localStorage` access so the package stays importable
|
|
1320
|
+
// in non-browser contexts (Node CLI / SSR); off the browser dev mode is off.
|
|
1321
|
+
static { this.isDevMode = typeof localStorage !== 'undefined' &&
|
|
1322
|
+
Truthy(localStorage.getItem('devMode')); }
|
|
1323
|
+
static colored(color, background, ...args) {
|
|
1324
|
+
if (!Logger.isDevMode) {
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
const [first, ...rest] = args;
|
|
1328
|
+
console.log.apply(console, [
|
|
1329
|
+
`%c ${timeUTCToString()} ${first} `,
|
|
1330
|
+
`color: ${color}; background: ${background};`,
|
|
1331
|
+
...rest,
|
|
1332
|
+
]);
|
|
1333
|
+
}
|
|
1334
|
+
static log(...args) {
|
|
1335
|
+
if (!Logger.isDevMode) {
|
|
1336
|
+
return;
|
|
1337
|
+
}
|
|
1338
|
+
console.log.apply(console, [
|
|
1339
|
+
`%c ${timeUTCToString()} [ LOG ] `,
|
|
1340
|
+
'color: black; background: #80ff80;',
|
|
1341
|
+
...args,
|
|
1342
|
+
]);
|
|
1343
|
+
}
|
|
1344
|
+
static warn(...args) {
|
|
1345
|
+
if (!Logger.isDevMode) {
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
console.warn.apply(console, [
|
|
1349
|
+
`%c ${timeUTCToString()} WARN `,
|
|
1350
|
+
'color: black; background: #ffd500;',
|
|
1351
|
+
...args,
|
|
1352
|
+
]);
|
|
1353
|
+
}
|
|
1354
|
+
static info(...args) {
|
|
1355
|
+
if (!Logger.isDevMode) {
|
|
1356
|
+
return;
|
|
1357
|
+
}
|
|
1358
|
+
console.log.apply(console, [
|
|
1359
|
+
`%c ${timeUTCToString()} [ INFO ] `,
|
|
1360
|
+
'color: white; background: blue;',
|
|
1361
|
+
...args,
|
|
1362
|
+
]);
|
|
1363
|
+
}
|
|
1364
|
+
static error(...args) {
|
|
1365
|
+
if (!Logger.isDevMode) {
|
|
1366
|
+
return;
|
|
1367
|
+
}
|
|
1368
|
+
console.error.apply(console, [
|
|
1369
|
+
`%c ${timeUTCToString()} ERROR `,
|
|
1370
|
+
'color: white; background: red;',
|
|
1371
|
+
...args,
|
|
1372
|
+
]);
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
/** Clamps `value` between `min` and `max`; an inverted range yields `min`. */
|
|
1377
|
+
function clampf(min, max, value) {
|
|
1378
|
+
if (min > max) {
|
|
1379
|
+
return min;
|
|
1380
|
+
}
|
|
1381
|
+
return Math.min(max, Math.max(min, value));
|
|
1382
|
+
}
|
|
1383
|
+
/** Linear interpolation; `value` is clamped to the 0..1 range first. */
|
|
1384
|
+
function lerp(min, max, value) {
|
|
1385
|
+
value = clampf(0, 1, value);
|
|
1386
|
+
return value * (max - min) + min;
|
|
1387
|
+
}
|
|
1388
|
+
/**
|
|
1389
|
+
* The inverse of {@link lerp}: where `value` sits between `min` and `max`.
|
|
1390
|
+
*
|
|
1391
|
+
* Returns 1 when the range is empty, to avoid dividing by zero.
|
|
1392
|
+
*/
|
|
1393
|
+
function inverseLerp(min, max, value, clampToNormal = false) {
|
|
1394
|
+
if (clampToNormal) {
|
|
1395
|
+
value = Math.min(max, value);
|
|
1396
|
+
value = Math.max(min, value);
|
|
1397
|
+
}
|
|
1398
|
+
const difference = max - min;
|
|
1399
|
+
if (difference === 0) {
|
|
1400
|
+
return 1;
|
|
1401
|
+
}
|
|
1402
|
+
const result = (value - min) / difference;
|
|
1403
|
+
if (clampToNormal) {
|
|
1404
|
+
return Math.min(1, Math.max(0, result));
|
|
1405
|
+
}
|
|
1406
|
+
return result;
|
|
1407
|
+
}
|
|
1408
|
+
const EPSILON = 0.01;
|
|
1409
|
+
/**
|
|
1410
|
+
* Floating-point equality within `Epsilon` (default `0.01`).
|
|
1411
|
+
*
|
|
1412
|
+
* Note the `||` fallback: passing `0` uses the default, it does not compare
|
|
1413
|
+
* exactly.
|
|
1414
|
+
*/
|
|
1415
|
+
function fpIsASameAsB(A, B, Epsilon) {
|
|
1416
|
+
Epsilon = Epsilon || EPSILON;
|
|
1417
|
+
return Math.abs(A - B) < Epsilon;
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
/**
|
|
1421
|
+
* A counting semaphore: `acquire()` resolves once a slot is free, `release()`
|
|
1422
|
+
* hands the slot to the longest-waiting caller.
|
|
1423
|
+
*/
|
|
1424
|
+
class Semaphore {
|
|
1425
|
+
constructor(maxConcurrency) {
|
|
1426
|
+
this.maxConcurrency = maxConcurrency;
|
|
1427
|
+
this.tasks = [];
|
|
1428
|
+
this.currentCount = 0;
|
|
1429
|
+
}
|
|
1430
|
+
acquire() {
|
|
1431
|
+
return new Promise((resolve) => {
|
|
1432
|
+
if (this.currentCount < this.maxConcurrency) {
|
|
1433
|
+
this.currentCount++;
|
|
1434
|
+
resolve();
|
|
1435
|
+
}
|
|
1436
|
+
else {
|
|
1437
|
+
this.tasks.push(resolve);
|
|
1438
|
+
}
|
|
1439
|
+
});
|
|
1440
|
+
}
|
|
1441
|
+
release() {
|
|
1442
|
+
if (this.tasks.length > 0) {
|
|
1443
|
+
const nextTask = this.tasks.shift();
|
|
1444
|
+
if (nextTask) {
|
|
1445
|
+
nextTask();
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
else if (this.currentCount > 0) {
|
|
1449
|
+
this.currentCount--;
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
const tapLog = (text, ...args) => (source) => source.pipe(tap((data) => {
|
|
1455
|
+
Logger.colored(...COLOR_CODES.TAP_LOG, text, data, ...args);
|
|
1456
|
+
}));
|
|
1457
|
+
|
|
1458
|
+
// Internal only. Deliberately absent from src/public-api.ts — these are the
|
|
1459
|
+
// symbols this package used to pull from @3dsource/utils. Exporting them would
|
|
1460
|
+
// re-create the coupling this folder exists to remove.
|
|
1461
|
+
//
|
|
1462
|
+
// Import this barrel from production code ('../utils' / '../../utils'), never
|
|
1463
|
+
// the individual files: the specs mock the barrel as a unit.
|
|
1464
|
+
|
|
828
1465
|
/**
|
|
829
1466
|
* `'metabox'` — the default when `UNREAL_CONFIG` omits `mode` — speaks the full
|
|
830
1467
|
* Metabox command protocol. `'default'` targets a stock Pixel Streaming
|
|
@@ -953,10 +1590,10 @@ class WebrtcErrorModalComponent {
|
|
|
953
1590
|
close() {
|
|
954
1591
|
this.#dialogRef.close();
|
|
955
1592
|
}
|
|
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.
|
|
1593
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: WebrtcErrorModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1594
|
+
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
1595
|
}
|
|
959
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
1596
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: WebrtcErrorModalComponent, decorators: [{
|
|
960
1597
|
type: Component,
|
|
961
1598
|
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
1599
|
}] });
|
|
@@ -1179,10 +1816,10 @@ class CommandTelemetryService extends SubService {
|
|
|
1179
1816
|
this.trackTime(out);
|
|
1180
1817
|
funcToDecorate(out);
|
|
1181
1818
|
}
|
|
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.
|
|
1819
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: CommandTelemetryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1820
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: CommandTelemetryService, providedIn: 'root' }); }
|
|
1184
1821
|
}
|
|
1185
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
1822
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: CommandTelemetryService, decorators: [{
|
|
1186
1823
|
type: Injectable,
|
|
1187
1824
|
args: [{ providedIn: 'root' }]
|
|
1188
1825
|
}], ctorParameters: () => [] });
|
|
@@ -1203,10 +1840,10 @@ class DevModeService {
|
|
|
1203
1840
|
localStorage.removeItem('devMode');
|
|
1204
1841
|
}
|
|
1205
1842
|
}
|
|
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.
|
|
1843
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: DevModeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1844
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: DevModeService, providedIn: 'root' }); }
|
|
1208
1845
|
}
|
|
1209
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
1846
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: DevModeService, decorators: [{
|
|
1210
1847
|
type: Injectable,
|
|
1211
1848
|
args: [{
|
|
1212
1849
|
providedIn: 'root',
|
|
@@ -1525,10 +2162,10 @@ class RegionsPingService {
|
|
|
1525
2162
|
}
|
|
1526
2163
|
}
|
|
1527
2164
|
}
|
|
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.
|
|
2165
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: RegionsPingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2166
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: RegionsPingService, providedIn: 'root' }); }
|
|
1530
2167
|
}
|
|
1531
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
2168
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: RegionsPingService, decorators: [{
|
|
1532
2169
|
type: Injectable,
|
|
1533
2170
|
args: [{ providedIn: 'root' }]
|
|
1534
2171
|
}], ctorParameters: () => [] });
|
|
@@ -1571,101 +2208,25 @@ function withStreamRequestId(wsUrl, streamRequestId) {
|
|
|
1571
2208
|
}
|
|
1572
2209
|
|
|
1573
2210
|
/**
|
|
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.
|
|
2211
|
+
* Creates a WebSocket and wraps it in a single-value Observable: emits the open
|
|
2212
|
+
* socket, then completes, so a downstream `tap` can attach handlers before any
|
|
2213
|
+
* message arrives.
|
|
1640
2214
|
*
|
|
1641
|
-
*
|
|
2215
|
+
* Ownership transfers to the consumer on emission — teardown never closes a
|
|
2216
|
+
* socket it already delivered, because `connectToCirrus` needs that connection
|
|
2217
|
+
* to stay alive.
|
|
1642
2218
|
*
|
|
1643
|
-
*
|
|
1644
|
-
*
|
|
1645
|
-
*
|
|
1646
|
-
*
|
|
1647
|
-
* at two levels:
|
|
2219
|
+
* An *undelivered* socket is orphaned and teardown must close it. `ws.close()`
|
|
2220
|
+
* on a `CONNECTING` socket does not reliably abort the HTTP upgrade in every
|
|
2221
|
+
* browser, so teardown also swaps in a one-shot `open` handler that closes the
|
|
2222
|
+
* socket if the handshake completes anyway.
|
|
1648
2223
|
*
|
|
1649
|
-
*
|
|
1650
|
-
*
|
|
1651
|
-
* 2. **Outside `retry`** (e.g. in `connectToSignaling`) — kills the entire
|
|
1652
|
-
* retry loop so no further re-subscriptions occur.
|
|
2224
|
+
* The outer `defer` gives every subscription a fresh socket, so `retry` does not
|
|
2225
|
+
* reuse a closed one.
|
|
1653
2226
|
*
|
|
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
|
-
* ```
|
|
2227
|
+
* There is no abort signal: cancellation is the caller's `takeUntil`, and it has
|
|
2228
|
+
* to sit at two levels — inside the per-attempt chain to cancel the in-flight
|
|
2229
|
+
* socket, and outside `retry` to stop the loop re-subscribing.
|
|
1669
2230
|
*
|
|
1670
2231
|
* @param wsUrl - The `ws://` or `wss://` URL to connect to.
|
|
1671
2232
|
* @returns Observable that emits a single open WebSocket, then completes.
|
|
@@ -1673,17 +2234,18 @@ function withStreamRequestId(wsUrl, streamRequestId) {
|
|
|
1673
2234
|
* does not support WebSocket.
|
|
1674
2235
|
*/
|
|
1675
2236
|
function createWebSocket(wsUrl, timeoutMs = WS_TIMEOUT) {
|
|
1676
|
-
//
|
|
2237
|
+
// SSR guard.
|
|
1677
2238
|
if (typeof window === 'undefined' || !('WebSocket' in window)) {
|
|
1678
2239
|
return throwError(() => new Error("Your browser doesn't support WebSocket"));
|
|
1679
2240
|
}
|
|
1680
2241
|
Logger.info('Creating socket', wsUrl);
|
|
1681
2242
|
return defer(() => new Observable((observer) => {
|
|
1682
2243
|
const ws = new WebSocket(wsUrl);
|
|
1683
|
-
//
|
|
2244
|
+
// `opened` guards `onClose` so it only errors on a close *before* the
|
|
2245
|
+
// connection was established; `emitted` tells teardown whether the
|
|
2246
|
+
// consumer already owns the socket.
|
|
1684
2247
|
let opened = false;
|
|
1685
2248
|
let emitted = false;
|
|
1686
|
-
// --- Event handlers (attached during connection, removed in teardown) ---
|
|
1687
2249
|
const onOpen = () => {
|
|
1688
2250
|
opened = true;
|
|
1689
2251
|
emitted = true;
|
|
@@ -1704,23 +2266,20 @@ function createWebSocket(wsUrl, timeoutMs = WS_TIMEOUT) {
|
|
|
1704
2266
|
ws.addEventListener('open', onOpen);
|
|
1705
2267
|
ws.addEventListener('error', onError);
|
|
1706
2268
|
ws.addEventListener('close', onClose);
|
|
1707
|
-
//
|
|
2269
|
+
// Teardown: unsubscribe, timeout, error, or complete.
|
|
1708
2270
|
return () => {
|
|
1709
2271
|
ws.removeEventListener('error', onError);
|
|
1710
2272
|
ws.removeEventListener('close', onClose);
|
|
1711
2273
|
if (!emitted &&
|
|
1712
2274
|
(ws.readyState === WebSocket.CONNECTING ||
|
|
1713
2275
|
ws.readyState === WebSocket.OPEN)) {
|
|
1714
|
-
//
|
|
1715
|
-
//
|
|
1716
|
-
// browser completes the handshake after this teardown, the
|
|
1717
|
-
// handler will close the orphaned socket immediately.
|
|
2276
|
+
// Orphaned: close it, and cover the case where the browser
|
|
2277
|
+
// completes the handshake after this teardown anyway.
|
|
1718
2278
|
ws.removeEventListener('open', onOpen);
|
|
1719
2279
|
ws.addEventListener('open', () => ws.close());
|
|
1720
|
-
// Some
|
|
1721
|
-
//
|
|
1722
|
-
//
|
|
1723
|
-
// the temporary handlers once the socket closes.
|
|
2280
|
+
// Some implementations (including `ws`) emit `error` when a
|
|
2281
|
+
// CONNECTING socket is closed. The observable is already torn
|
|
2282
|
+
// down, so swallow it and drop the handlers on close.
|
|
1724
2283
|
const onOrphanError = () => undefined;
|
|
1725
2284
|
const onOrphanClose = () => {
|
|
1726
2285
|
ws.removeEventListener('error', onOrphanError);
|
|
@@ -1731,8 +2290,7 @@ function createWebSocket(wsUrl, timeoutMs = WS_TIMEOUT) {
|
|
|
1731
2290
|
ws.close();
|
|
1732
2291
|
}
|
|
1733
2292
|
else {
|
|
1734
|
-
//
|
|
1735
|
-
// Just remove our internal listener; don't touch the socket.
|
|
2293
|
+
// Delivered — the consumer owns it; only drop our listener.
|
|
1736
2294
|
ws.removeEventListener('open', onOpen);
|
|
1737
2295
|
}
|
|
1738
2296
|
};
|
|
@@ -2366,10 +2924,10 @@ class SignallingService extends SubService {
|
|
|
2366
2924
|
Logger.log('Start Getting Region');
|
|
2367
2925
|
return this.regionsPingService.getFastest().pipe(take(1));
|
|
2368
2926
|
}
|
|
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.
|
|
2927
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SignallingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2928
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SignallingService, providedIn: 'root' }); }
|
|
2371
2929
|
}
|
|
2372
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
2930
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SignallingService, decorators: [{
|
|
2373
2931
|
type: Injectable,
|
|
2374
2932
|
args: [{ providedIn: 'root' }]
|
|
2375
2933
|
}], ctorParameters: () => [] });
|
|
@@ -2784,10 +3342,10 @@ class VideoService extends SubService {
|
|
|
2784
3342
|
this.armGestureRetry(audio);
|
|
2785
3343
|
}
|
|
2786
3344
|
}
|
|
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.
|
|
3345
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: VideoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3346
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: VideoService, providedIn: 'root' }); }
|
|
2789
3347
|
}
|
|
2790
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
3348
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: VideoService, decorators: [{
|
|
2791
3349
|
type: Injectable,
|
|
2792
3350
|
args: [{ providedIn: 'root' }]
|
|
2793
3351
|
}], ctorParameters: () => [] });
|
|
@@ -3453,10 +4011,10 @@ class WebRtcPlayerService extends SubService {
|
|
|
3453
4011
|
Logger.error("Couldn't create answer", e);
|
|
3454
4012
|
}
|
|
3455
4013
|
}
|
|
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.
|
|
4014
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: WebRtcPlayerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4015
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: WebRtcPlayerService, providedIn: 'root' }); }
|
|
3458
4016
|
}
|
|
3459
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
4017
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: WebRtcPlayerService, decorators: [{
|
|
3460
4018
|
type: Injectable,
|
|
3461
4019
|
args: [{ providedIn: 'root' }]
|
|
3462
4020
|
}], ctorParameters: () => [] });
|
|
@@ -3626,10 +4184,10 @@ class StreamAdoptionService {
|
|
|
3626
4184
|
this.webRtc.adopt(parked.pc, parked.dc, parked.stream, parked.config ?? {}, parked.dcBuffer);
|
|
3627
4185
|
return true;
|
|
3628
4186
|
}
|
|
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.
|
|
4187
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StreamAdoptionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4188
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StreamAdoptionService, providedIn: 'root' }); }
|
|
3631
4189
|
}
|
|
3632
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
4190
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StreamAdoptionService, decorators: [{
|
|
3633
4191
|
type: Injectable,
|
|
3634
4192
|
args: [{ providedIn: 'root' }]
|
|
3635
4193
|
}] });
|
|
@@ -3697,10 +4255,10 @@ class UnrealCallbackService {
|
|
|
3697
4255
|
return observable;
|
|
3698
4256
|
});
|
|
3699
4257
|
}
|
|
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.
|
|
4258
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealCallbackService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4259
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealCallbackService, providedIn: 'root' }); }
|
|
3702
4260
|
}
|
|
3703
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
4261
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealCallbackService, decorators: [{
|
|
3704
4262
|
type: Injectable,
|
|
3705
4263
|
args: [{ providedIn: 'root' }]
|
|
3706
4264
|
}] });
|
|
@@ -3817,10 +4375,10 @@ class UnrealCommunicatorService extends SubService {
|
|
|
3817
4375
|
requestQualityControl() {
|
|
3818
4376
|
this.sendInputData(new Uint8Array([MessageType.RequestQualityControl]).buffer);
|
|
3819
4377
|
}
|
|
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.
|
|
4378
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealCommunicatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4379
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealCommunicatorService, providedIn: 'root' }); }
|
|
3822
4380
|
}
|
|
3823
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
4381
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealCommunicatorService, decorators: [{
|
|
3824
4382
|
type: Injectable,
|
|
3825
4383
|
args: [{ providedIn: 'root' }]
|
|
3826
4384
|
}], ctorParameters: () => [] });
|
|
@@ -3834,10 +4392,10 @@ class UnrealErrorModalComponent {
|
|
|
3834
4392
|
close() {
|
|
3835
4393
|
this.#dialogRef.close();
|
|
3836
4394
|
}
|
|
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.
|
|
4395
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealErrorModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4396
|
+
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
4397
|
}
|
|
3840
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
4398
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealErrorModalComponent, decorators: [{
|
|
3841
4399
|
type: Component,
|
|
3842
4400
|
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
4401
|
}] });
|
|
@@ -4233,10 +4791,10 @@ class UnrealEffects {
|
|
|
4233
4791
|
// Fails silently if cross-origin
|
|
4234
4792
|
}
|
|
4235
4793
|
}
|
|
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.
|
|
4794
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealEffects, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4795
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealEffects }); }
|
|
4238
4796
|
}
|
|
4239
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
4797
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealEffects, decorators: [{
|
|
4240
4798
|
type: Injectable
|
|
4241
4799
|
}] });
|
|
4242
4800
|
|
|
@@ -4388,10 +4946,9 @@ const floatToSmoothPercents = () => (source) => source.pipe(timestamp(), startWi
|
|
|
4388
4946
|
* Smoothly interpolates from `start` to `end` over `duration`ms using the
|
|
4389
4947
|
* animation frame scheduler. Completes when the transition finishes.
|
|
4390
4948
|
*
|
|
4391
|
-
*
|
|
4392
|
-
*
|
|
4393
|
-
*
|
|
4394
|
-
* Not exported: internal to `floatToSmoothPercents`.
|
|
4949
|
+
* Deliberately local. The version this was forked from never completed — it
|
|
4950
|
+
* lacked `takeWhile(... < 1, true)` — which would deadlock the `concatMap`
|
|
4951
|
+
* above. Not exported: internal to `floatToSmoothPercents`.
|
|
4395
4952
|
*/
|
|
4396
4953
|
const smoothTransition = (start, end, duration) => {
|
|
4397
4954
|
const startTime = animationFrameScheduler.now();
|
|
@@ -4753,10 +5310,10 @@ class AFKService extends SubService {
|
|
|
4753
5310
|
}
|
|
4754
5311
|
}, 1000);
|
|
4755
5312
|
}
|
|
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.
|
|
5313
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AFKService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5314
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AFKService, providedIn: 'root' }); }
|
|
4758
5315
|
}
|
|
4759
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
5316
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AFKService, decorators: [{
|
|
4760
5317
|
type: Injectable,
|
|
4761
5318
|
args: [{ providedIn: 'root' }]
|
|
4762
5319
|
}], ctorParameters: () => [] });
|
|
@@ -4806,10 +5363,10 @@ class LoadingProgressService {
|
|
|
4806
5363
|
// `switchMap` cancels the inner subscription on every visibility change
|
|
4807
5364
|
// so stale emissions can't leak through.
|
|
4808
5365
|
#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.
|
|
5366
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: LoadingProgressService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5367
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: LoadingProgressService, providedIn: 'root' }); }
|
|
4811
5368
|
}
|
|
4812
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
5369
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: LoadingProgressService, decorators: [{
|
|
4813
5370
|
type: Injectable,
|
|
4814
5371
|
args: [{ providedIn: 'root' }]
|
|
4815
5372
|
}] });
|
|
@@ -4895,10 +5452,10 @@ class FreezeFrameService extends SubService {
|
|
|
4895
5452
|
progress: 1,
|
|
4896
5453
|
}));
|
|
4897
5454
|
}
|
|
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.
|
|
5455
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FreezeFrameService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5456
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FreezeFrameService, providedIn: 'root' }); }
|
|
4900
5457
|
}
|
|
4901
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
5458
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FreezeFrameService, decorators: [{
|
|
4902
5459
|
type: Injectable,
|
|
4903
5460
|
args: [{ providedIn: 'root' }]
|
|
4904
5461
|
}], ctorParameters: () => [] });
|
|
@@ -5050,19 +5607,21 @@ class FileReceiverService extends SubService {
|
|
|
5050
5607
|
this.reset();
|
|
5051
5608
|
}
|
|
5052
5609
|
}
|
|
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.
|
|
5610
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FileReceiverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5611
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FileReceiverService, providedIn: 'root' }); }
|
|
5055
5612
|
}
|
|
5056
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
5613
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FileReceiverService, decorators: [{
|
|
5057
5614
|
type: Injectable,
|
|
5058
5615
|
args: [{ providedIn: 'root' }]
|
|
5059
5616
|
}], ctorParameters: () => [] });
|
|
5060
5617
|
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5618
|
+
/**
|
|
5619
|
+
* Matches the normalisation the old `where()` predicate applied to both sides:
|
|
5620
|
+
* trim, collapse space runs to `_`, lowercase.
|
|
5621
|
+
*/
|
|
5622
|
+
const normalizeCommand = (value) => String(value).trim().replace(/ +/gi, '_').toLowerCase();
|
|
5623
|
+
/** Commands whose arrival is not worth a console line. */
|
|
5624
|
+
const FILTERED_LOG_COMMANDS = new Set(['onChangeSequence'].map(normalizeCommand));
|
|
5066
5625
|
class AggregatorService extends SubService {
|
|
5067
5626
|
constructor() {
|
|
5068
5627
|
super();
|
|
@@ -5149,7 +5708,11 @@ class AggregatorService extends SubService {
|
|
|
5149
5708
|
});
|
|
5150
5709
|
}
|
|
5151
5710
|
showMessageFromUnreal(json) {
|
|
5152
|
-
|
|
5711
|
+
// The `undefined` check is redundant while the set holds only real command
|
|
5712
|
+
// names, but `where()` ignored undefined criteria outright — keep it so an
|
|
5713
|
+
// entry literally named 'undefined' could never start matching.
|
|
5714
|
+
if (json?.command !== undefined &&
|
|
5715
|
+
FILTERED_LOG_COMMANDS.has(normalizeCommand(json.command))) {
|
|
5153
5716
|
return;
|
|
5154
5717
|
}
|
|
5155
5718
|
Logger.colored(...COLOR_CODES.FROM_UNREAL, json);
|
|
@@ -5232,10 +5795,10 @@ class AggregatorService extends SubService {
|
|
|
5232
5795
|
Logger.warn(`unrecognized data received, packet ID ${view[0]}`);
|
|
5233
5796
|
}
|
|
5234
5797
|
}
|
|
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.
|
|
5798
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AggregatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5799
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AggregatorService, providedIn: 'root' }); }
|
|
5237
5800
|
}
|
|
5238
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
5801
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AggregatorService, decorators: [{
|
|
5239
5802
|
type: Injectable,
|
|
5240
5803
|
args: [{ providedIn: 'root' }]
|
|
5241
5804
|
}], ctorParameters: () => [] });
|
|
@@ -5396,10 +5959,10 @@ class ConsoleExtensionsService extends SubService {
|
|
|
5396
5959
|
Logger.info('emitCommand(command) => send command to Unreal Engine.');
|
|
5397
5960
|
Logger.info('stressTest({iterations}) => hammer reconnect: repeatedly drop DC/PC and assert recovery.');
|
|
5398
5961
|
}
|
|
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.
|
|
5962
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ConsoleExtensionsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
5963
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ConsoleExtensionsService, providedIn: 'root' }); }
|
|
5401
5964
|
}
|
|
5402
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
5965
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ConsoleExtensionsService, decorators: [{
|
|
5403
5966
|
type: Injectable,
|
|
5404
5967
|
args: [{ providedIn: 'root' }]
|
|
5405
5968
|
}], ctorParameters: () => [] });
|
|
@@ -5413,30 +5976,48 @@ const RESIZE_DEBOUNCE_MS = 300;
|
|
|
5413
5976
|
const FUNCTION_KEY_MIN = 112;
|
|
5414
5977
|
const FUNCTION_KEY_MAX = 123;
|
|
5415
5978
|
const TAB_KEY_CODE = 9;
|
|
5979
|
+
// VK_LEFT..VK_DOWN. Held down, these scroll the page while they steer the
|
|
5980
|
+
// camera, so they belong with the keys `suppressBrowserKeys` neutralises.
|
|
5981
|
+
const ARROW_KEY_MIN = 37;
|
|
5982
|
+
const ARROW_KEY_MAX = 40;
|
|
5983
|
+
/** Elements that own the keyboard while focused — never forward to the stream. */
|
|
5984
|
+
const TEXT_ENTRY_SELECTOR = 'input, textarea, select, [contenteditable]:not([contenteditable="false"])';
|
|
5416
5985
|
class InputService extends SubService {
|
|
5417
5986
|
constructor() {
|
|
5418
5987
|
super();
|
|
5419
5988
|
this.commandsSender = inject(UnrealCommunicatorService);
|
|
5420
|
-
|
|
5989
|
+
// The service, not its value: `isDevMode` is a getter over localStorage, and
|
|
5990
|
+
// `setDevMode()` is documented as callable from the console at runtime.
|
|
5991
|
+
this.devModeService = inject(DevModeService);
|
|
5421
5992
|
this.videoService = inject(VideoService);
|
|
5422
5993
|
this.unrealConfig = inject(UNREAL_CONFIG, { optional: true });
|
|
5994
|
+
// Physical key names (`KeyboardEvent.code`), which is what the allow-list is
|
|
5995
|
+
// matched against. The numpad digits are deliberately absent: with NumLock
|
|
5996
|
+
// off they *are* the arrows, but the browser reports them under their own
|
|
5997
|
+
// `code`, so enabling them here would forward a second set of arrow keys.
|
|
5998
|
+
// A consumer that wants them passes them to `useKeyboardKeys`.
|
|
5423
5999
|
this.defaultKeys = [
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
6000
|
+
'KeyW',
|
|
6001
|
+
'KeyS',
|
|
6002
|
+
'KeyA',
|
|
6003
|
+
'KeyD',
|
|
6004
|
+
'ArrowUp',
|
|
6005
|
+
'ArrowDown',
|
|
6006
|
+
'ArrowLeft',
|
|
6007
|
+
'ArrowRight',
|
|
6008
|
+
'NumpadAdd',
|
|
6009
|
+
'NumpadSubtract',
|
|
6010
|
+
// Both Control keys. Only `ControlRight` was ever declared here, but the
|
|
6011
|
+
// numeric allow-list resolved 17 to `'ControlLeft'`, so the left one is what
|
|
6012
|
+
// actually reached the engine — dropping it now would be a regression for
|
|
6013
|
+
// the more commonly pressed of the two.
|
|
6014
|
+
'ControlLeft',
|
|
6015
|
+
'ControlRight',
|
|
6016
|
+
'Equal',
|
|
6017
|
+
'Minus',
|
|
6018
|
+
'NumpadDecimal',
|
|
5438
6019
|
];
|
|
5439
|
-
this.availableKeys = this.defaultKeys;
|
|
6020
|
+
this.availableKeys = new Set(this.defaultKeys);
|
|
5440
6021
|
this.options = InputOptions;
|
|
5441
6022
|
this.reInit$ = new Subject();
|
|
5442
6023
|
this.deactivatedVideoTrigger$ = NEVER;
|
|
@@ -5453,6 +6034,12 @@ class InputService extends SubService {
|
|
|
5453
6034
|
this.fingerIds = new Map();
|
|
5454
6035
|
this.maxByteValue = 255;
|
|
5455
6036
|
this.fingers = [...INITIAL_FINGER_IDS];
|
|
6037
|
+
// Virtual-key codes for which a KeyDown has been sent and no KeyUp yet. This
|
|
6038
|
+
// is the sole gate on KeyUp, which makes the pairing an invariant instead of
|
|
6039
|
+
// something the filters have to agree on twice: a key the engine was never
|
|
6040
|
+
// told about cannot be released, and a key it was told about is always
|
|
6041
|
+
// released — including when the browser never delivers the `keyup` at all.
|
|
6042
|
+
this.heldKeys = new Set();
|
|
5456
6043
|
// Reusable wire buffers. Input events fire at up to ~60 Hz; the data channel
|
|
5457
6044
|
// copies the bytes synchronously on sending (RTCDataChannel.send), so a single
|
|
5458
6045
|
// buffer per message shape is safe and avoids per-event allocation/GC churn.
|
|
@@ -5485,8 +6072,17 @@ class InputService extends SubService {
|
|
|
5485
6072
|
.pipe(filter(() => !!this.video), takeUntil$1(this.destroy$))
|
|
5486
6073
|
.subscribe(() => this.setup());
|
|
5487
6074
|
}
|
|
6075
|
+
/**
|
|
6076
|
+
* Replaces the forwarded-key allow-list. Takes physical key names
|
|
6077
|
+
* (`KeyboardEvent.code`) such as `'KeyW'` or `'BracketLeft'`.
|
|
6078
|
+
*
|
|
6079
|
+
* Legacy numeric `keyCode` values are still accepted and converted, but they
|
|
6080
|
+
* cannot express every key: `InvertedKeyMap` is many-to-one, so 37 resolves
|
|
6081
|
+
* to `'ArrowLeft'` and 17 to `'ControlLeft'`, and `'Numpad4'`/`'ControlRight'`
|
|
6082
|
+
* are unreachable through the numeric form. Pass names.
|
|
6083
|
+
*/
|
|
5488
6084
|
useKeyboardKeys(keys) {
|
|
5489
|
-
this.availableKeys = keys;
|
|
6085
|
+
this.availableKeys = new Set(keys.map((key) => (typeof key === 'number' ? InvertedKeyMap[key] : key)));
|
|
5490
6086
|
}
|
|
5491
6087
|
get video() {
|
|
5492
6088
|
return this.videoService.video;
|
|
@@ -5501,6 +6097,10 @@ class InputService extends SubService {
|
|
|
5501
6097
|
// Reset touch state to prevent stale identifiers across sessions
|
|
5502
6098
|
this.fingerIds.clear();
|
|
5503
6099
|
this.fingers = [...INITIAL_FINGER_IDS];
|
|
6100
|
+
// Same for the key registry: a key held across a reconnect belongs to the
|
|
6101
|
+
// previous engine session, and releasing it into the new one is worse than
|
|
6102
|
+
// dropping it.
|
|
6103
|
+
this.heldKeys.clear();
|
|
5504
6104
|
merge(fromResizeObserver(video), this.actions$.pipe(ofType(videoAdaptedToContainer)))
|
|
5505
6105
|
.pipe(debounceTime$1(RESIZE_DEBOUNCE_MS), takeUntil$1(this.deactivatedVideoTrigger$))
|
|
5506
6106
|
.subscribe(() => this.setupNormalizeAndQuantize(video));
|
|
@@ -5588,9 +6188,17 @@ class InputService extends SubService {
|
|
|
5588
6188
|
fromEvent(window, 'blur')
|
|
5589
6189
|
.pipe(filter(() => !!video), takeUntil$1(this.deactivatedVideoTrigger$))
|
|
5590
6190
|
.subscribe(() => this.releaseMouseButtons(255, 0, 0));
|
|
6191
|
+
// Deliberately *not* gated on `deactivatedVideoTrigger$`: that trigger
|
|
6192
|
+
// includes the visibility-hidden event, so a subscription behind it is torn
|
|
6193
|
+
// down by the very event this one has to react to. `reInit$` alone is
|
|
6194
|
+
// enough to avoid stacking duplicates across `setup()` calls, since
|
|
6195
|
+
// `setup()` fires it before it gets here.
|
|
6196
|
+
merge(fromEvent(window, 'blur'), fromEvent(document, 'visibilitychange').pipe(filter(() => document.visibilityState === 'hidden')))
|
|
6197
|
+
.pipe(takeUntil$1(merge(this.reInit$, this.destroy$)))
|
|
6198
|
+
.subscribe(() => this.releaseKeys());
|
|
5591
6199
|
this.registerMouseEnterAndLeaveEvents(video);
|
|
5592
6200
|
this.registerHoveringMouseEvents(video);
|
|
5593
|
-
this.registerKeyboardEvents(
|
|
6201
|
+
this.registerKeyboardEvents();
|
|
5594
6202
|
this.registerTouchEvents(video);
|
|
5595
6203
|
}
|
|
5596
6204
|
getTouchPositionWithOffset({ clientX, clientY }) {
|
|
@@ -5812,62 +6420,108 @@ class InputService extends SubService {
|
|
|
5812
6420
|
this.releaseMouseButtons(e.buttons, e.offsetX, e.offsetY);
|
|
5813
6421
|
});
|
|
5814
6422
|
}
|
|
5815
|
-
|
|
5816
|
-
|
|
6423
|
+
/**
|
|
6424
|
+
* Keys whose default browser action fights the stream: the function keys
|
|
6425
|
+
* (F5 reloads mid-session), Tab (moves focus out of the player) and the
|
|
6426
|
+
* arrows (scroll the page while they steer the camera).
|
|
6427
|
+
*
|
|
6428
|
+
* Takes the *resolved* virtual-key code rather than `event.code`, so a numpad
|
|
6429
|
+
* key acting as an arrow with NumLock off is caught as well.
|
|
6430
|
+
*/
|
|
6431
|
+
isBrowserKey(keyCode) {
|
|
5817
6432
|
return ((keyCode >= FUNCTION_KEY_MIN && keyCode <= FUNCTION_KEY_MAX) ||
|
|
6433
|
+
(keyCode >= ARROW_KEY_MIN && keyCode <= ARROW_KEY_MAX) ||
|
|
5818
6434
|
keyCode === TAB_KEY_CODE);
|
|
5819
6435
|
}
|
|
5820
6436
|
/**
|
|
5821
|
-
* The key code Unreal expects
|
|
6437
|
+
* The key code Unreal expects — the Windows virtual-key code — or `null` when
|
|
6438
|
+
* the event carries no key worth forwarding.
|
|
5822
6439
|
*
|
|
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.
|
|
6440
|
+
* `KeyboardNumericCode` covers only the keys whose `event.keyCode` cannot be
|
|
6441
|
+
* trusted; everything else, the numpad included, falls through to the value
|
|
6442
|
+
* the browser resolved.
|
|
5828
6443
|
*
|
|
5829
|
-
*
|
|
5830
|
-
*
|
|
6444
|
+
* Returns `null` for an IME composition — `event.code` still names the
|
|
6445
|
+
* physical key there, so the keystrokes would otherwise reach the engine as
|
|
6446
|
+
* camera movement — and for a `keyCode` of 0, which no engine key uses.
|
|
5831
6447
|
*/
|
|
5832
6448
|
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
|
-
|
|
6449
|
+
if (e.keyCode === IME_PROCESS_KEY) {
|
|
6450
|
+
return null;
|
|
6451
|
+
}
|
|
6452
|
+
const keyCode = KeyboardNumericCode[e.code] ??
|
|
6453
|
+
e.keyCode;
|
|
6454
|
+
return keyCode || null;
|
|
6455
|
+
}
|
|
6456
|
+
/**
|
|
6457
|
+
* True while a focused element owns the keyboard. Read off `composedPath()`
|
|
6458
|
+
* rather than `event.target`: retargeting reports the host element for an
|
|
6459
|
+
* `<input>` inside a shadow root, so a `target`-based check never fires in an
|
|
6460
|
+
* app built from web components.
|
|
6461
|
+
*/
|
|
6462
|
+
isTextEntryTarget(e) {
|
|
6463
|
+
const target = e.composedPath()[0] ?? e.target;
|
|
6464
|
+
return target instanceof Element && !!target.closest(TEXT_ENTRY_SELECTOR);
|
|
6465
|
+
}
|
|
6466
|
+
/** True when `event.code` is on the allow-list, or dev mode waives it. */
|
|
6467
|
+
isKeyAllowed(e) {
|
|
6468
|
+
if (this.availableKeys.has(e.code)) {
|
|
6469
|
+
return true;
|
|
6470
|
+
}
|
|
6471
|
+
if (!this.devModeService.isDevMode) {
|
|
6472
|
+
return false;
|
|
6473
|
+
}
|
|
6474
|
+
// Once per press, not once per keydown/keyup/keypress and not on autorepeat.
|
|
6475
|
+
if (e.type === 'keydown' && !e.repeat) {
|
|
6476
|
+
Logger.warn('Code=>', e.code, 'Keyboard event is not filtered in DEV Mode. App may behave inappropriately!');
|
|
6477
|
+
}
|
|
6478
|
+
return true;
|
|
6479
|
+
}
|
|
6480
|
+
sendKeyUp(keyCode) {
|
|
6481
|
+
const keyUp = this.keyUpBytes;
|
|
6482
|
+
keyUp[0] = MessageType.KeyUp;
|
|
6483
|
+
keyUp[1] = keyCode;
|
|
6484
|
+
this.sendInputData(keyUp.buffer);
|
|
5855
6485
|
}
|
|
5856
|
-
|
|
5857
|
-
|
|
6486
|
+
/**
|
|
6487
|
+
* Releases everything the engine still believes is held. Needed because a
|
|
6488
|
+
* `keyup` is not guaranteed to arrive: the window can lose focus to a browser
|
|
6489
|
+
* dialog or another tab first, and then the engine keeps moving the camera
|
|
6490
|
+
* forever.
|
|
6491
|
+
*/
|
|
6492
|
+
releaseKeys() {
|
|
6493
|
+
for (const keyCode of this.heldKeys) {
|
|
6494
|
+
this.sendKeyUp(keyCode);
|
|
6495
|
+
}
|
|
6496
|
+
this.heldKeys.clear();
|
|
6497
|
+
}
|
|
6498
|
+
registerKeyboardEvents() {
|
|
5858
6499
|
fromEvent(document, 'keydown')
|
|
5859
6500
|
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
5860
6501
|
.subscribe((e) => {
|
|
5861
|
-
|
|
6502
|
+
// A focused field owns the key outright — no forwarding and no
|
|
6503
|
+
// `preventDefault`, or Tab could not move between inputs.
|
|
6504
|
+
if (this.isTextEntryTarget(e)) {
|
|
5862
6505
|
return;
|
|
5863
6506
|
}
|
|
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
6507
|
const keyCode = this.getKeyCode(e);
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
6508
|
+
if (keyCode === null) {
|
|
6509
|
+
return;
|
|
6510
|
+
}
|
|
6511
|
+
// Ahead of the allow-list on purpose. None of the browser keys are
|
|
6512
|
+
// forwarded, so a check that sits behind the allow-list can never run,
|
|
6513
|
+
// which is what made `suppressBrowserKeys` a no-op.
|
|
6514
|
+
if (this.options.suppressBrowserKeys && this.isBrowserKey(keyCode)) {
|
|
6515
|
+
e.preventDefault();
|
|
6516
|
+
}
|
|
6517
|
+
if (!this.isKeyAllowed(e)) {
|
|
6518
|
+
return;
|
|
6519
|
+
}
|
|
6520
|
+
// A browser shortcut is in flight (Ctrl+W closes the tab, Ctrl+S opens
|
|
6521
|
+
// a dialog, Ctrl+= zooms). The browser acts on it regardless, so the
|
|
6522
|
+
// engine must not also treat it as gameplay input. Modifier keys are
|
|
6523
|
+
// exempt: their own keydown already reports themselves as pressed.
|
|
6524
|
+
if ((e.ctrlKey || e.metaKey) && !MODIFIER_KEY_CODES.has(e.code)) {
|
|
5871
6525
|
return;
|
|
5872
6526
|
}
|
|
5873
6527
|
const keyDown = this.keyDownBytes;
|
|
@@ -5875,38 +6529,46 @@ class InputService extends SubService {
|
|
|
5875
6529
|
keyDown[1] = keyCode;
|
|
5876
6530
|
keyDown[2] = Number(e.repeat);
|
|
5877
6531
|
this.sendInputData(keyDown.buffer);
|
|
6532
|
+
this.heldKeys.add(keyCode);
|
|
5878
6533
|
// Backspace isn't a keypress in JS, but UE4 text-entry fields need it
|
|
5879
6534
|
// to delete characters.
|
|
5880
|
-
if (
|
|
6535
|
+
if (keyCode === SpecialKeyCodes.BackSpace) {
|
|
5881
6536
|
const data = this.keyPressView;
|
|
5882
6537
|
data.setUint8(0, MessageType.KeyPress);
|
|
5883
6538
|
data.setUint16(1, SpecialKeyCodes.BackSpace, true);
|
|
5884
6539
|
this.sendInputData(data.buffer);
|
|
5885
6540
|
}
|
|
5886
|
-
if (this.options.suppressBrowserKeys &&
|
|
5887
|
-
this.isKeyCodeBrowserKey(e.keyCode)) {
|
|
5888
|
-
e.preventDefault();
|
|
5889
|
-
}
|
|
5890
6541
|
});
|
|
5891
6542
|
fromEvent(document, 'keyup')
|
|
5892
6543
|
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
5893
6544
|
.subscribe((e) => {
|
|
5894
|
-
|
|
6545
|
+
const keyCode = this.getKeyCode(e);
|
|
6546
|
+
if (keyCode === null) {
|
|
5895
6547
|
return;
|
|
5896
6548
|
}
|
|
5897
|
-
const keyUp = this.keyUpBytes;
|
|
5898
|
-
keyUp[0] = MessageType.KeyUp;
|
|
5899
|
-
keyUp[1] = this.getKeyCode(e);
|
|
5900
|
-
this.sendInputData(keyUp.buffer);
|
|
5901
6549
|
if (this.options.suppressBrowserKeys &&
|
|
5902
|
-
this.
|
|
6550
|
+
this.isBrowserKey(keyCode) &&
|
|
6551
|
+
!this.isTextEntryTarget(e)) {
|
|
5903
6552
|
e.preventDefault();
|
|
5904
6553
|
}
|
|
6554
|
+
// The registry is the only gate here. Re-running the allow-list and the
|
|
6555
|
+
// focus check would let their state drift between press and release —
|
|
6556
|
+
// press over the video, release with a dialog focused, and the engine
|
|
6557
|
+
// never hears the key came up.
|
|
6558
|
+
if (!this.heldKeys.delete(keyCode)) {
|
|
6559
|
+
return;
|
|
6560
|
+
}
|
|
6561
|
+
this.sendKeyUp(keyCode);
|
|
5905
6562
|
});
|
|
5906
6563
|
fromEvent(document, 'keypress')
|
|
5907
6564
|
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
5908
6565
|
.subscribe((e) => {
|
|
5909
|
-
if (
|
|
6566
|
+
if (this.isTextEntryTarget(e) || !this.isKeyAllowed(e)) {
|
|
6567
|
+
return;
|
|
6568
|
+
}
|
|
6569
|
+
// Deprecated event: the payload is a character, so an IME composition
|
|
6570
|
+
// or a key with no character produces nothing to send.
|
|
6571
|
+
if (e.keyCode === IME_PROCESS_KEY || !e.charCode) {
|
|
5910
6572
|
return;
|
|
5911
6573
|
}
|
|
5912
6574
|
const data = this.keyPressView;
|
|
@@ -5915,10 +6577,10 @@ class InputService extends SubService {
|
|
|
5915
6577
|
this.sendInputData(data.buffer);
|
|
5916
6578
|
});
|
|
5917
6579
|
}
|
|
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.
|
|
6580
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: InputService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
6581
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: InputService, providedIn: 'root' }); }
|
|
5920
6582
|
}
|
|
5921
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
6583
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: InputService, decorators: [{
|
|
5922
6584
|
type: Injectable,
|
|
5923
6585
|
args: [{ providedIn: 'root' }]
|
|
5924
6586
|
}], ctorParameters: () => [] });
|
|
@@ -5987,46 +6649,36 @@ class StreamStatusTelemetryService extends SubService {
|
|
|
5987
6649
|
VideoEncoderQP,
|
|
5988
6650
|
};
|
|
5989
6651
|
}
|
|
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.
|
|
6652
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StreamStatusTelemetryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
6653
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StreamStatusTelemetryService, providedIn: 'root' }); }
|
|
5992
6654
|
}
|
|
5993
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
6655
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StreamStatusTelemetryService, decorators: [{
|
|
5994
6656
|
type: Injectable,
|
|
5995
6657
|
args: [{ providedIn: 'root' }]
|
|
5996
6658
|
}], ctorParameters: () => [] });
|
|
5997
6659
|
|
|
5998
6660
|
/**
|
|
5999
|
-
*
|
|
6661
|
+
* Telemetry for the WebRTC stream lifecycle.
|
|
6000
6662
|
*
|
|
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
|
|
6663
|
+
* The event taxonomy is deliberately small — phase-specific detail rides inside
|
|
6664
|
+
* `stream.phase_ended`'s payload rather than becoming its own event type:
|
|
6665
|
+
* `session_started`, `phase_ended` (once per closer in {@link phaseCatalog}),
|
|
6666
|
+
* `sample` (every 5s, window-aggregated), `quality_degraded` /
|
|
6667
|
+
* `quality_recovered` (QP entering/leaving `red`), `fps_low`, `session_ended`.
|
|
6668
|
+
* Every wire shape lives in `interfaces/stream-telemetry-events.interface.ts`,
|
|
6669
|
+
* and `track()` / `emitLifecycle()` are typed against it — a drifting payload is
|
|
6670
|
+
* a compile error.
|
|
6013
6671
|
*
|
|
6014
|
-
*
|
|
6015
|
-
*
|
|
6016
|
-
*
|
|
6017
|
-
*
|
|
6018
|
-
* answered, the first events are queued and flushed with it (see
|
|
6672
|
+
* `sessionId` IS the stream's connection id (`selectCirrusConnectionId`), the
|
|
6673
|
+
* value the debug overlay labels "Connection Id", so a telemetry session can be
|
|
6674
|
+
* matched to a Cirrus player session. That id only exists once orchestration
|
|
6675
|
+
* answered, so early events are queued and flushed with it (see
|
|
6019
6676
|
* {@link SessionState.wireId}); a session that never got one falls back to a
|
|
6020
|
-
*
|
|
6021
|
-
*
|
|
6022
|
-
* jumps.
|
|
6677
|
+
* local uuid. Samples carry a monotonic `seq` for server-side ordering and
|
|
6678
|
+
* dedup, and durations use `performance.now()` to survive wall-clock jumps.
|
|
6023
6679
|
*
|
|
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.
|
|
6680
|
+
* NOTE: `stream.session_ended` only survives tab close if the Mixpanel client
|
|
6681
|
+
* is configured with `api_transport: 'sendBeacon'`.
|
|
6030
6682
|
*/
|
|
6031
6683
|
/** Trim a resource URL to its path: drop origin and query string so the
|
|
6032
6684
|
* emitted name is short, stable, and not a PII-bearing query. */
|
|
@@ -6351,45 +7003,31 @@ class StreamStatusTelemetryService2 {
|
|
|
6351
7003
|
}
|
|
6352
7004
|
}
|
|
6353
7005
|
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.
|
|
7006
|
+
// Bound to `setEstablishingConnection(true)`, not `initSignalling`, which
|
|
7007
|
+
// fires several times per page load (unreal-scene effect, `startStream`,
|
|
7008
|
+
// reconnect). `connectToSignaling$` collapses those into one attempt
|
|
7009
|
+
// (`exhaustMap` + `!cirrusConnected`), and its `startWith(...)` is the
|
|
7010
|
+
// single dispatch site for `true` — downstream of that guard and ahead of
|
|
7011
|
+
// both branches (prefetch adoption / fresh connect). So this yields one
|
|
7012
|
+
// session per real attempt instead of a burst of `restart` churn, while
|
|
7013
|
+
// genuine reconnects still end the prior session as `restart`.
|
|
6366
7014
|
//
|
|
6367
|
-
// Do NOT add a second dispatch site:
|
|
6368
|
-
// `
|
|
6369
|
-
//
|
|
7015
|
+
// Do NOT add a second dispatch site: every extra `true` becomes
|
|
7016
|
+
// `endSession('restart')` + a new session, discarding the first session's
|
|
7017
|
+
// page-load measurement and its prefetch adoption.
|
|
6370
7018
|
this.actions$
|
|
6371
7019
|
.pipe(ofType(setEstablishingConnection), filter$1(({ value }) => value === true), takeUntil$1(this.destroy$))
|
|
6372
7020
|
.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:
|
|
7021
|
+
// End triggers read the action stream, not the state, on purpose. The
|
|
7022
|
+
// `destroyUnrealScene` reducer resets the whole unreal state in one step,
|
|
7023
|
+
// so `cirrusConnected` flips to `false` while `disconnectReason` resets to
|
|
7024
|
+
// `None`. A state subscriber fires synchronously inside that emission —
|
|
7025
|
+
// before the follow-up effect writes `Destroy` back — and would report
|
|
7026
|
+
// `'disconnected'`. Per-action subscriptions pick the right reason instead,
|
|
7027
|
+
// and `endSession` is idempotent, so a cascading second trigger is a no-op:
|
|
6389
7028
|
// - `destroyUnrealScene` → `'destroy'` (route change, removed from DOM)
|
|
6390
|
-
// - `setCirrusDisconnected` → `'disconnected'` (WS close, AFK,
|
|
6391
|
-
//
|
|
6392
|
-
// read from current state in `endSession`)
|
|
7029
|
+
// - `setCirrusDisconnected` → `'disconnected'` (WS close, AFK, manual
|
|
7030
|
+
// drop, WebRTCError — granular cause read from state in `endSession`)
|
|
6393
7031
|
this.actions$
|
|
6394
7032
|
.pipe(ofType(destroyUnrealScene), takeUntil$1(this.destroy$))
|
|
6395
7033
|
.subscribe(() => this.endSession('destroy'));
|
|
@@ -6685,11 +7323,10 @@ class StreamStatusTelemetryService2 {
|
|
|
6685
7323
|
/**
|
|
6686
7324
|
* Emit the region / signaling / webrtc phases for an ADOPTED connection.
|
|
6687
7325
|
*
|
|
6688
|
-
* The prefetch script established the connection in
|
|
6689
|
-
* so
|
|
6690
|
-
*
|
|
6691
|
-
*
|
|
6692
|
-
* happened while the page was loading. Each phase ships:
|
|
7326
|
+
* The prefetch script established the connection in parallel with page load,
|
|
7327
|
+
* so phases sit at their real anchor-relative spans — shifted left to overlap
|
|
7328
|
+
* the HTML-loading / route-idle rows instead of following them. Each phase
|
|
7329
|
+
* ships:
|
|
6693
7330
|
* - `duration` — the real sub-step time the prefetch spent.
|
|
6694
7331
|
* - `spanStartMs` — anchor-relative start, so the viewer left-shifts the bar.
|
|
6695
7332
|
* - `adoptionAtMs` — where Angular took over (the next phase, Unreal
|
|
@@ -6955,22 +7592,15 @@ class StreamStatusTelemetryService2 {
|
|
|
6955
7592
|
}
|
|
6956
7593
|
}
|
|
6957
7594
|
/**
|
|
6958
|
-
*
|
|
6959
|
-
*
|
|
6960
|
-
*
|
|
7595
|
+
* Aggregates `performance.getEntriesByType('resource')` by `initiatorType`,
|
|
7596
|
+
* split at `window.load`: `resources` for entries before `loadEventEnd` (the
|
|
7597
|
+
* actual page weight) and `lazyResources` for those after it (typically the
|
|
7598
|
+
* route's lazy chunks and manifests, downloaded when the user navigates to the
|
|
7599
|
+
* sub-route the streamer lives on). If `loadEventEnd` is 0 or unknown,
|
|
7600
|
+
* everything lands in `resources` and `lazyResources` is null.
|
|
6961
7601
|
*
|
|
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.
|
|
7602
|
+
* `transferSize === 0 && decodedBodySize > 0` means an HTTP-cache hit, counted
|
|
7603
|
+
* separately so it does not inflate the bytes-on-the-wire metric.
|
|
6974
7604
|
*/
|
|
6975
7605
|
collectResourceTotals(loadEventEnd) {
|
|
6976
7606
|
try {
|
|
@@ -7092,10 +7722,10 @@ class StreamStatusTelemetryService2 {
|
|
|
7092
7722
|
emit(event, data) {
|
|
7093
7723
|
this.store.dispatch(trackTelemetryData({ event, data }));
|
|
7094
7724
|
}
|
|
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.
|
|
7725
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StreamStatusTelemetryService2, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
7726
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StreamStatusTelemetryService2, providedIn: 'root' }); }
|
|
7097
7727
|
}
|
|
7098
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
7728
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StreamStatusTelemetryService2, decorators: [{
|
|
7099
7729
|
type: Injectable,
|
|
7100
7730
|
args: [{ providedIn: 'root' }]
|
|
7101
7731
|
}], ctorParameters: () => [] });
|
|
@@ -7181,10 +7811,10 @@ class FileHandlerService {
|
|
|
7181
7811
|
return observable;
|
|
7182
7812
|
});
|
|
7183
7813
|
}
|
|
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.
|
|
7814
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FileHandlerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
7815
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FileHandlerService, providedIn: 'root' }); }
|
|
7186
7816
|
}
|
|
7187
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
7817
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FileHandlerService, decorators: [{
|
|
7188
7818
|
type: Injectable,
|
|
7189
7819
|
args: [{ providedIn: 'root' }]
|
|
7190
7820
|
}] });
|
|
@@ -7273,86 +7903,31 @@ class AnalyticsService extends SubService {
|
|
|
7273
7903
|
Logger.log('Analytics Event:', name, params);
|
|
7274
7904
|
this.store.dispatch(saveAnalyticsEvent({ event: { name, params } }));
|
|
7275
7905
|
}
|
|
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.
|
|
7906
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AnalyticsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
7907
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AnalyticsService, providedIn: 'root' }); }
|
|
7278
7908
|
}
|
|
7279
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
7909
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AnalyticsService, decorators: [{
|
|
7280
7910
|
type: Injectable,
|
|
7281
7911
|
args: [{ providedIn: 'root' }]
|
|
7282
7912
|
}], ctorParameters: () => [] });
|
|
7283
7913
|
|
|
7284
7914
|
/**
|
|
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 |
|
|
7915
|
+
* Adaptive FPS controller: watches the incoming WebRTC stream and steers Unreal's
|
|
7916
|
+
* `t.MaxFPS` between the discrete {@link FPS_STEPS}.
|
|
7305
7917
|
*
|
|
7306
|
-
*
|
|
7918
|
+
* Every {@link SAMPLE_WINDOW} ticks of `VideoService.videoStats$` (250 ms each)
|
|
7919
|
+
* it averages FPS, bitrate and QP, runs them through the fuzzy membership
|
|
7920
|
+
* functions below, and picks a decision by first-match rules. Fuzzy bands rather
|
|
7921
|
+
* than hard thresholds so a metric sitting on a boundary does not oscillate.
|
|
7307
7922
|
*
|
|
7308
|
-
*
|
|
7923
|
+
* Cooldowns between steps are deliberately asymmetric: stepping *down* again is
|
|
7924
|
+
* allowed after {@link COOLDOWN_DECREASE_AFTER_DECREASE_MS}, but stepping back
|
|
7925
|
+
* *up* after a decrease waits {@link COOLDOWN_INCREASE_AFTER_DECREASE_MS} — a
|
|
7926
|
+
* stream that just failed its target is likely to fail it again.
|
|
7309
7927
|
*
|
|
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.
|
|
7928
|
+
* Changes go out as the `setMaxFps` action, not a direct command: the existing
|
|
7929
|
+
* `UnrealEffects.setMaxFps$` effect turns it into the `t.MaxFPS <value>` console
|
|
7930
|
+
* command.
|
|
7356
7931
|
*/
|
|
7357
7932
|
class FpsMonitorService extends SubService {
|
|
7358
7933
|
constructor() {
|
|
@@ -7453,15 +8028,7 @@ class FpsMonitorService extends SubService {
|
|
|
7453
8028
|
const decision = this.evaluateDecision(avg, currentTarget);
|
|
7454
8029
|
this.upgradeFps(decision, avg.qp);
|
|
7455
8030
|
}
|
|
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
|
-
*/
|
|
8031
|
+
/** Rules are evaluated in priority order — first match wins. */
|
|
7465
8032
|
evaluateDecision(avg, currentTarget) {
|
|
7466
8033
|
const referenceTarget = currentTarget > 0 ? currentTarget : this.UNLIMITED_REFERENCE_FPS;
|
|
7467
8034
|
const fpsRatio = avg.fps / referenceTarget;
|
|
@@ -7501,21 +8068,10 @@ class FpsMonitorService extends SubService {
|
|
|
7501
8068
|
}
|
|
7502
8069
|
return 'hold';
|
|
7503
8070
|
}
|
|
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
|
-
*/
|
|
8071
|
+
// Fuzzy membership functions: normalised input (0..1+) → membership degree
|
|
8072
|
+
// (0..1). The shapes overlap on purpose, so several bands can be partially
|
|
8073
|
+
// active at once and the rules stay less brittle than hard thresholds.
|
|
8074
|
+
/** "low" — the stream cannot keep up with its target. */
|
|
7519
8075
|
membershipFpsLow(ratio) {
|
|
7520
8076
|
if (ratio < 0.7)
|
|
7521
8077
|
return 1.0;
|
|
@@ -7523,15 +8079,7 @@ class FpsMonitorService extends SubService {
|
|
|
7523
8079
|
return 0.0;
|
|
7524
8080
|
return (0.9 - ratio) / 0.2;
|
|
7525
8081
|
}
|
|
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
|
-
*/
|
|
8082
|
+
/** "ok" — triangle peaking just under the target. */
|
|
7535
8083
|
membershipFpsOk(ratio) {
|
|
7536
8084
|
if (ratio < 0.8)
|
|
7537
8085
|
return 0.0;
|
|
@@ -7541,14 +8089,7 @@ class FpsMonitorService extends SubService {
|
|
|
7541
8089
|
return (1.0 - ratio) / 0.05;
|
|
7542
8090
|
return 0.0;
|
|
7543
8091
|
}
|
|
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
|
-
*/
|
|
8092
|
+
/** "high" — the stream meets or exceeds its target. */
|
|
7552
8093
|
membershipFpsHigh(ratio) {
|
|
7553
8094
|
if (ratio < 0.9)
|
|
7554
8095
|
return 0.0;
|
|
@@ -7556,14 +8097,7 @@ class FpsMonitorService extends SubService {
|
|
|
7556
8097
|
return 1.0;
|
|
7557
8098
|
return (ratio - 0.9) / 0.1;
|
|
7558
8099
|
}
|
|
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
|
-
*/
|
|
8100
|
+
/** "high" — the encoder is using most of the available bandwidth. */
|
|
7567
8101
|
membershipBitrateHigh(load) {
|
|
7568
8102
|
if (load < 0.5)
|
|
7569
8103
|
return 0.0;
|
|
@@ -7643,10 +8177,10 @@ class FpsMonitorService extends SubService {
|
|
|
7643
8177
|
}
|
|
7644
8178
|
return { fps: fps / len, bitrate: bitrate / len, qp: qp / len };
|
|
7645
8179
|
}
|
|
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.
|
|
8180
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FpsMonitorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
8181
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FpsMonitorService, providedIn: 'root' }); }
|
|
7648
8182
|
}
|
|
7649
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8183
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FpsMonitorService, decorators: [{
|
|
7650
8184
|
type: Injectable,
|
|
7651
8185
|
args: [{ providedIn: 'root' }]
|
|
7652
8186
|
}], ctorParameters: () => [] });
|
|
@@ -7681,10 +8215,10 @@ class AfkTimeoutModalComponent {
|
|
|
7681
8215
|
resetAfk() {
|
|
7682
8216
|
this.#afkService.reset();
|
|
7683
8217
|
}
|
|
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.
|
|
8218
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AfkTimeoutModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8219
|
+
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
8220
|
}
|
|
7687
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8221
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AfkTimeoutModalComponent, decorators: [{
|
|
7688
8222
|
type: Component,
|
|
7689
8223
|
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
8224
|
}], 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 +8230,10 @@ class FreezeFrameComponent {
|
|
|
7696
8230
|
this.combinedFreeze = this.#store.selectSignal(selectFreezeFrameCombinedDataUrl);
|
|
7697
8231
|
}
|
|
7698
8232
|
#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.
|
|
8233
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FreezeFrameComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8234
|
+
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
8235
|
}
|
|
7702
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8236
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: FreezeFrameComponent, decorators: [{
|
|
7703
8237
|
type: Component,
|
|
7704
8238
|
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
8239
|
}] });
|
|
@@ -7714,10 +8248,10 @@ class ImageLoadingSrcComponent {
|
|
|
7714
8248
|
loadingImageError() {
|
|
7715
8249
|
this.#store.dispatch(setLoadingImageSrc({ src: '' }));
|
|
7716
8250
|
}
|
|
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.
|
|
8251
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ImageLoadingSrcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8252
|
+
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
8253
|
}
|
|
7720
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8254
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ImageLoadingSrcComponent, decorators: [{
|
|
7721
8255
|
type: Component,
|
|
7722
8256
|
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
8257
|
}] });
|
|
@@ -7800,10 +8334,10 @@ class StatGraphComponent {
|
|
|
7800
8334
|
}
|
|
7801
8335
|
this.draw();
|
|
7802
8336
|
}
|
|
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.
|
|
8337
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StatGraphComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8338
|
+
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
8339
|
}
|
|
7806
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8340
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: StatGraphComponent, decorators: [{
|
|
7807
8341
|
type: Component,
|
|
7808
8342
|
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
8343
|
}], 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 +8352,10 @@ class UnrealResumeSlotDirective {
|
|
|
7818
8352
|
static ngTemplateContextGuard(_dir, _ctx) {
|
|
7819
8353
|
return true;
|
|
7820
8354
|
}
|
|
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.
|
|
8355
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealResumeSlotDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
8356
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: UnrealResumeSlotDirective, isStandalone: true, selector: "ng-template[unrealResumeSlot]", ngImport: i0 }); }
|
|
7823
8357
|
}
|
|
7824
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8358
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealResumeSlotDirective, decorators: [{
|
|
7825
8359
|
type: Directive,
|
|
7826
8360
|
args: [{ selector: 'ng-template[unrealResumeSlot]' }]
|
|
7827
8361
|
}] });
|
|
@@ -7832,10 +8366,10 @@ class UnrealAfkSlotDirective {
|
|
|
7832
8366
|
static ngTemplateContextGuard(_dir, _ctx) {
|
|
7833
8367
|
return true;
|
|
7834
8368
|
}
|
|
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.
|
|
8369
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealAfkSlotDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
8370
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: UnrealAfkSlotDirective, isStandalone: true, selector: "ng-template[unrealAfkSlot]", ngImport: i0 }); }
|
|
7837
8371
|
}
|
|
7838
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8372
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealAfkSlotDirective, decorators: [{
|
|
7839
8373
|
type: Directive,
|
|
7840
8374
|
args: [{ selector: 'ng-template[unrealAfkSlot]' }]
|
|
7841
8375
|
}] });
|
|
@@ -7846,10 +8380,10 @@ class UnrealStatusSlotDirective {
|
|
|
7846
8380
|
static ngTemplateContextGuard(_dir, _ctx) {
|
|
7847
8381
|
return true;
|
|
7848
8382
|
}
|
|
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.
|
|
8383
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealStatusSlotDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
8384
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.3", type: UnrealStatusSlotDirective, isStandalone: true, selector: "ng-template[unrealStatusSlot]", ngImport: i0 }); }
|
|
7851
8385
|
}
|
|
7852
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8386
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealStatusSlotDirective, decorators: [{
|
|
7853
8387
|
type: Directive,
|
|
7854
8388
|
args: [{ selector: 'ng-template[unrealStatusSlot]' }]
|
|
7855
8389
|
}] });
|
|
@@ -7872,10 +8406,10 @@ class UnrealSpinnerComponent {
|
|
|
7872
8406
|
this.viewBox = computed(() => `0 0 ${this.size()} ${this.size()}`, /* @ts-ignore */
|
|
7873
8407
|
...(ngDevMode ? [{ debugName: "viewBox" }] : /* istanbul ignore next */ []));
|
|
7874
8408
|
}
|
|
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.
|
|
8409
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealSpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8410
|
+
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
8411
|
}
|
|
7878
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8412
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealSpinnerComponent, decorators: [{
|
|
7879
8413
|
type: Component,
|
|
7880
8414
|
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
8415
|
}], 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 +8440,10 @@ class UnrealStatusComponent {
|
|
|
7906
8440
|
}
|
|
7907
8441
|
#store;
|
|
7908
8442
|
#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.
|
|
8443
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealStatusComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8444
|
+
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
8445
|
}
|
|
7912
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8446
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealStatusComponent, decorators: [{
|
|
7913
8447
|
type: Component,
|
|
7914
8448
|
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
8449
|
}], 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 +8476,10 @@ class SafePipe {
|
|
|
7942
8476
|
// content instead of disabling framework security checks.
|
|
7943
8477
|
return (this.sanitizer.sanitize(context, value) ?? '');
|
|
7944
8478
|
}
|
|
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.
|
|
8479
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SafePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
8480
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.3", ngImport: i0, type: SafePipe, isStandalone: true, name: "safe" }); }
|
|
7947
8481
|
}
|
|
7948
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8482
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SafePipe, decorators: [{
|
|
7949
8483
|
type: Pipe,
|
|
7950
8484
|
args: [{
|
|
7951
8485
|
name: 'safe',
|
|
@@ -8058,10 +8592,10 @@ class VideoStatsComponent {
|
|
|
8058
8592
|
elements: this.elementsToShow(),
|
|
8059
8593
|
}));
|
|
8060
8594
|
}
|
|
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.
|
|
8595
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: VideoStatsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8596
|
+
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
8597
|
}
|
|
8064
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8598
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: VideoStatsComponent, decorators: [{
|
|
8065
8599
|
type: Component,
|
|
8066
8600
|
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
8601
|
}], ctorParameters: () => [] });
|
|
@@ -8123,10 +8657,10 @@ class ResumeStreamButtonComponent {
|
|
|
8123
8657
|
disconnect() {
|
|
8124
8658
|
this.isSecondStart.set(true);
|
|
8125
8659
|
}
|
|
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.
|
|
8660
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ResumeStreamButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8661
|
+
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
8662
|
}
|
|
8129
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8663
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ResumeStreamButtonComponent, decorators: [{
|
|
8130
8664
|
type: Component,
|
|
8131
8665
|
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
8666
|
}], 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 +8727,10 @@ class IntroSrcComponent {
|
|
|
8193
8727
|
sourceElement.addEventListener('error', () => this.#store.dispatch(resetIntroSrc()));
|
|
8194
8728
|
videoContainer.appendChild(videoElement);
|
|
8195
8729
|
}
|
|
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.
|
|
8730
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: IntroSrcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8731
|
+
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
8732
|
}
|
|
8199
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8733
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: IntroSrcComponent, decorators: [{
|
|
8200
8734
|
type: Component,
|
|
8201
8735
|
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
8736
|
}], ctorParameters: () => [], propDecorators: { videoElement: [{ type: i0.ViewChild, args: ['videoPlayerCover', { isSignal: true }] }] } });
|
|
@@ -8427,10 +8961,10 @@ class UnrealSceneComponent {
|
|
|
8427
8961
|
},
|
|
8428
8962
|
});
|
|
8429
8963
|
}
|
|
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 }); }
|
|
8964
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealSceneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
8965
|
+
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
8966
|
}
|
|
8433
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.
|
|
8967
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: UnrealSceneComponent, decorators: [{
|
|
8434
8968
|
type: Component,
|
|
8435
8969
|
args: [{ selector: 'app-unreal-scene', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
8436
8970
|
AfkTimeoutModalComponent,
|
|
@@ -8500,5 +9034,5 @@ function provideUnrealModule() {
|
|
|
8500
9034
|
* Generated bundle index. Do not edit.
|
|
8501
9035
|
*/
|
|
8502
9036
|
|
|
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 };
|
|
9037
|
+
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
9038
|
//# sourceMappingURL=3dsource-angular-unreal-module.mjs.map
|