@3dsource/angular-unreal-module 0.0.175 → 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.
- package/README.md +50 -19
- package/fesm2022/3dsource-angular-unreal-module-config.mjs +10 -0
- package/fesm2022/3dsource-angular-unreal-module-config.mjs.map +1 -0
- package/fesm2022/3dsource-angular-unreal-module.mjs +1055 -507
- package/fesm2022/3dsource-angular-unreal-module.mjs.map +1 -1
- package/package.json +8 -4
- package/types/3dsource-angular-unreal-module-config.d.ts +27 -0
- package/types/3dsource-angular-unreal-module.d.ts +246 -165
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, output, ChangeDetectionStrategy, Component,
|
|
2
|
+
import { input, output, ChangeDetectionStrategy, Component, inject, DestroyRef, Injectable, signal, effect, untracked, computed, ElementRef, viewChild, afterNextRender, HostListener, TemplateRef, Directive, SecurityContext, Pipe, contentChild, makeEnvironmentProviders, provideEnvironmentInitializer } from '@angular/core';
|
|
3
3
|
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 {
|
|
8
|
-
|
|
7
|
+
import { UNREAL_CONFIG } from '@3dsource/angular-unreal-module/config';
|
|
8
|
+
export { UNREAL_CONFIG } from '@3dsource/angular-unreal-module/config';
|
|
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';
|
|
9
11
|
import { DialogRef, DIALOG_DATA, Dialog } from '@angular/cdk/dialog';
|
|
10
12
|
import { HttpClient } from '@angular/common/http';
|
|
11
13
|
import { ScrollStrategyOptions } from '@angular/cdk/overlay';
|
|
@@ -34,10 +36,10 @@ class UnrealButtonComponent {
|
|
|
34
36
|
event.preventDefault();
|
|
35
37
|
this.clicked.emit(event);
|
|
36
38
|
}
|
|
37
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
38
|
-
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 }); }
|
|
39
41
|
}
|
|
40
|
-
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: [{
|
|
41
43
|
type: Component,
|
|
42
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"] }]
|
|
43
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"] }] } });
|
|
@@ -305,6 +307,157 @@ const MouseButtonsMask = {
|
|
|
305
307
|
FifthButton: 16, // Browser Forward button.
|
|
306
308
|
};
|
|
307
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
|
+
|
|
308
461
|
const ControlScheme = {
|
|
309
462
|
// A mouse can lock inside the WebRTC player, so the user can simply move the
|
|
310
463
|
// mouse to control the orientation of the camera. The user presses the
|
|
@@ -370,7 +523,19 @@ const ToClientMessage = {
|
|
|
370
523
|
Protocol: 255,
|
|
371
524
|
};
|
|
372
525
|
|
|
373
|
-
|
|
526
|
+
/**
|
|
527
|
+
* Re-export only. `UNREAL_CONFIG` lives in the `config` secondary entry point so
|
|
528
|
+
* that an app can provide it without pulling the engine in.
|
|
529
|
+
*
|
|
530
|
+
* The package is one FESM: esbuild puts a module in the common-ancestor chunk of
|
|
531
|
+
* its importers, so importing the token from the primary entry point in an eager
|
|
532
|
+
* `app.config.ts` hoists the whole engine into `main` — measured at ~180 kB raw
|
|
533
|
+
* (~49 kB gzip) in a metabox production build. Importing
|
|
534
|
+
* `@3dsource/angular-unreal-module/config` instead costs nothing but the token.
|
|
535
|
+
*
|
|
536
|
+
* Kept here so every existing consumer of the primary entry point, and the 26
|
|
537
|
+
* files inside this library, keep working unchanged.
|
|
538
|
+
*/
|
|
374
539
|
|
|
375
540
|
const InputOptions = {
|
|
376
541
|
controlScheme: ControlScheme.Default,
|
|
@@ -477,8 +642,12 @@ const UnrealStatusMessage = {
|
|
|
477
642
|
};
|
|
478
643
|
|
|
479
644
|
const COMMAND_EXILE_TIMEOUT_MS = 10_000;
|
|
645
|
+
const normalizeId = (value) => String(value).trim().replace(/ +/gi, '_').toLowerCase();
|
|
480
646
|
function exileExpiredCommands(commandsInProgress, idToRemove, now) {
|
|
481
|
-
|
|
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);
|
|
482
651
|
const expired = remaining.filter(({ timeStamp }) => now - timeStamp > COMMAND_EXILE_TIMEOUT_MS);
|
|
483
652
|
if (expired.length) {
|
|
484
653
|
const expiredIds = new Set(expired.map(({ id }) => id));
|
|
@@ -811,6 +980,488 @@ const unrealFeature = createFeature({
|
|
|
811
980
|
reducer: unrealReducer,
|
|
812
981
|
});
|
|
813
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
|
+
|
|
814
1465
|
/**
|
|
815
1466
|
* `'metabox'` — the default when `UNREAL_CONFIG` omits `mode` — speaks the full
|
|
816
1467
|
* Metabox command protocol. `'default'` targets a stock Pixel Streaming
|
|
@@ -939,10 +1590,10 @@ class WebrtcErrorModalComponent {
|
|
|
939
1590
|
close() {
|
|
940
1591
|
this.#dialogRef.close();
|
|
941
1592
|
}
|
|
942
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
943
|
-
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 }); }
|
|
944
1595
|
}
|
|
945
|
-
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: [{
|
|
946
1597
|
type: Component,
|
|
947
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"] }]
|
|
948
1599
|
}] });
|
|
@@ -1165,10 +1816,10 @@ class CommandTelemetryService extends SubService {
|
|
|
1165
1816
|
this.trackTime(out);
|
|
1166
1817
|
funcToDecorate(out);
|
|
1167
1818
|
}
|
|
1168
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
1169
|
-
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' }); }
|
|
1170
1821
|
}
|
|
1171
|
-
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: [{
|
|
1172
1823
|
type: Injectable,
|
|
1173
1824
|
args: [{ providedIn: 'root' }]
|
|
1174
1825
|
}], ctorParameters: () => [] });
|
|
@@ -1189,10 +1840,10 @@ class DevModeService {
|
|
|
1189
1840
|
localStorage.removeItem('devMode');
|
|
1190
1841
|
}
|
|
1191
1842
|
}
|
|
1192
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
1193
|
-
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' }); }
|
|
1194
1845
|
}
|
|
1195
|
-
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: [{
|
|
1196
1847
|
type: Injectable,
|
|
1197
1848
|
args: [{
|
|
1198
1849
|
providedIn: 'root',
|
|
@@ -1511,10 +2162,10 @@ class RegionsPingService {
|
|
|
1511
2162
|
}
|
|
1512
2163
|
}
|
|
1513
2164
|
}
|
|
1514
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
1515
|
-
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' }); }
|
|
1516
2167
|
}
|
|
1517
|
-
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: [{
|
|
1518
2169
|
type: Injectable,
|
|
1519
2170
|
args: [{ providedIn: 'root' }]
|
|
1520
2171
|
}], ctorParameters: () => [] });
|
|
@@ -1557,101 +2208,25 @@ function withStreamRequestId(wsUrl, streamRequestId) {
|
|
|
1557
2208
|
}
|
|
1558
2209
|
|
|
1559
2210
|
/**
|
|
1560
|
-
*
|
|
1561
|
-
*
|
|
1562
|
-
*
|
|
1563
|
-
* once the connection is established, then completes. This design allows
|
|
1564
|
-
* downstream operators (e.g. `tap` in `connectToCirrus`) to attach their own
|
|
1565
|
-
* event handlers before any messages arrive.
|
|
1566
|
-
*
|
|
1567
|
-
* ## Ownership model
|
|
1568
|
-
*
|
|
1569
|
-
* The factory **transfers ownership** of the WebSocket to the consumer upon
|
|
1570
|
-
* emission. Once `observer.next(ws)` fires, the consumer is responsible for
|
|
1571
|
-
* the socket's lifecycle (attaching handlers, closing when done). The teardown
|
|
1572
|
-
* logic will **never** close a socket that has been successfully delivered.
|
|
1573
|
-
*
|
|
1574
|
-
* ## Timeout
|
|
1575
|
-
*
|
|
1576
|
-
* The observable is piped through `timeout({ first: WS_TIMEOUT })`. If the
|
|
1577
|
-
* WebSocket `open` event does not fire within `WS_TIMEOUT` milliseconds, the
|
|
1578
|
-
* stream errors with a timeout message and the teardown disposes the socket.
|
|
1579
|
-
*
|
|
1580
|
-
* ## Teardown & leak prevention
|
|
1581
|
-
*
|
|
1582
|
-
* When the observable is unsubscribed (timeout, manual unsubscribe, or error),
|
|
1583
|
-
* the teardown function runs and handles two cases:
|
|
1584
|
-
*
|
|
1585
|
-
* 1. **Socket was emitted (`emitted === true`):** The consumer owns the socket.
|
|
1586
|
-
* Teardown only removes the internal event listeners — it does NOT close
|
|
1587
|
-
* the socket. Closing it here would break downstream consumers like
|
|
1588
|
-
* `connectToCirrus` that rely on the connection staying alive.
|
|
1589
|
-
*
|
|
1590
|
-
* 2. **Socket was NOT emitted (`emitted === false`):** The socket is orphaned
|
|
1591
|
-
* (nobody has a reference to it). Teardown must close it to prevent a leak.
|
|
1592
|
-
* However, calling `ws.close()` on a `CONNECTING` socket does not reliably
|
|
1593
|
-
* abort the underlying HTTP upgrade request in all browsers — the TCP
|
|
1594
|
-
* handshake may still complete asynchronously. To handle this edge case,
|
|
1595
|
-
* teardown replaces the `open` listener with a one-shot handler that calls
|
|
1596
|
-
* `ws.close()` if the connection succeeds after teardown has already run.
|
|
1597
|
-
* This ensures the orphaned socket is closed regardless of timing:
|
|
1598
|
-
*
|
|
1599
|
-
* - If `close()` aborts the connection immediately — done.
|
|
1600
|
-
* - If the browser lets the handshake complete anyway — the `open` handler
|
|
1601
|
-
* fires and closes the now-connected socket, so it doesn't linger in
|
|
1602
|
-
* the browser's network tab as a "Pending" request.
|
|
1603
|
-
*
|
|
1604
|
-
* ## Why `defer`?
|
|
1605
|
-
*
|
|
1606
|
-
* The outer `defer()` ensures a **new WebSocket** is created on each
|
|
1607
|
-
* subscription. Without it, retry operators would reuse the same (possibly
|
|
1608
|
-
* closed) socket instance. With `defer`, each retry gets a fresh connection.
|
|
1609
|
-
*
|
|
1610
|
-
* ## SSR guard
|
|
1611
|
-
*
|
|
1612
|
-
* If `window` or `WebSocket` is not available (server-side rendering),
|
|
1613
|
-
* the function returns an error observable immediately without attempting
|
|
1614
|
-
* a connection.
|
|
1615
|
-
*
|
|
1616
|
-
* ## Lifecycle flags
|
|
1617
|
-
*
|
|
1618
|
-
* - `opened` — set to `true` when the `open` event fires. Guards the `close`
|
|
1619
|
-
* handler so it only errors the observable if the socket was closed *before*
|
|
1620
|
-
* the connection was established (e.g. server rejected the upgrade).
|
|
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.
|
|
1621
2214
|
*
|
|
1622
|
-
*
|
|
1623
|
-
*
|
|
1624
|
-
*
|
|
1625
|
-
* leaves it for the consumer.
|
|
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.
|
|
1626
2218
|
*
|
|
1627
|
-
*
|
|
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.
|
|
1628
2223
|
*
|
|
1629
|
-
* The
|
|
1630
|
-
*
|
|
1631
|
-
* `takeUntil` (or manual `unsubscribe`) fires, the observable tears down
|
|
1632
|
-
* and the orphaned socket is closed. For retry loops, place `takeUntil`
|
|
1633
|
-
* at two levels:
|
|
2224
|
+
* The outer `defer` gives every subscription a fresh socket, so `retry` does not
|
|
2225
|
+
* reuse a closed one.
|
|
1634
2226
|
*
|
|
1635
|
-
*
|
|
1636
|
-
*
|
|
1637
|
-
*
|
|
1638
|
-
* retry loop so no further re-subscriptions occur.
|
|
1639
|
-
*
|
|
1640
|
-
* ## Usage
|
|
1641
|
-
*
|
|
1642
|
-
* ```typescript
|
|
1643
|
-
* // In connectToCirrus — takeUntil cancels the current attempt:
|
|
1644
|
-
* createWebSocket(wsUrl).pipe(
|
|
1645
|
-
* takeUntil(abort$),
|
|
1646
|
-
* tap(ws => addWsHandlers(ws)),
|
|
1647
|
-
* );
|
|
1648
|
-
*
|
|
1649
|
-
* // In connectToSignaling — takeUntil outside retry kills the loop:
|
|
1650
|
-
* defer(() => innerChain$).pipe(
|
|
1651
|
-
* retry({ delay: ... }),
|
|
1652
|
-
* takeUntil(abort$),
|
|
1653
|
-
* );
|
|
1654
|
-
* ```
|
|
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.
|
|
1655
2230
|
*
|
|
1656
2231
|
* @param wsUrl - The `ws://` or `wss://` URL to connect to.
|
|
1657
2232
|
* @returns Observable that emits a single open WebSocket, then completes.
|
|
@@ -1659,17 +2234,18 @@ function withStreamRequestId(wsUrl, streamRequestId) {
|
|
|
1659
2234
|
* does not support WebSocket.
|
|
1660
2235
|
*/
|
|
1661
2236
|
function createWebSocket(wsUrl, timeoutMs = WS_TIMEOUT) {
|
|
1662
|
-
//
|
|
2237
|
+
// SSR guard.
|
|
1663
2238
|
if (typeof window === 'undefined' || !('WebSocket' in window)) {
|
|
1664
2239
|
return throwError(() => new Error("Your browser doesn't support WebSocket"));
|
|
1665
2240
|
}
|
|
1666
2241
|
Logger.info('Creating socket', wsUrl);
|
|
1667
2242
|
return defer(() => new Observable((observer) => {
|
|
1668
2243
|
const ws = new WebSocket(wsUrl);
|
|
1669
|
-
//
|
|
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.
|
|
1670
2247
|
let opened = false;
|
|
1671
2248
|
let emitted = false;
|
|
1672
|
-
// --- Event handlers (attached during connection, removed in teardown) ---
|
|
1673
2249
|
const onOpen = () => {
|
|
1674
2250
|
opened = true;
|
|
1675
2251
|
emitted = true;
|
|
@@ -1690,23 +2266,20 @@ function createWebSocket(wsUrl, timeoutMs = WS_TIMEOUT) {
|
|
|
1690
2266
|
ws.addEventListener('open', onOpen);
|
|
1691
2267
|
ws.addEventListener('error', onError);
|
|
1692
2268
|
ws.addEventListener('close', onClose);
|
|
1693
|
-
//
|
|
2269
|
+
// Teardown: unsubscribe, timeout, error, or complete.
|
|
1694
2270
|
return () => {
|
|
1695
2271
|
ws.removeEventListener('error', onError);
|
|
1696
2272
|
ws.removeEventListener('close', onClose);
|
|
1697
2273
|
if (!emitted &&
|
|
1698
2274
|
(ws.readyState === WebSocket.CONNECTING ||
|
|
1699
2275
|
ws.readyState === WebSocket.OPEN)) {
|
|
1700
|
-
//
|
|
1701
|
-
//
|
|
1702
|
-
// browser completes the handshake after this teardown, the
|
|
1703
|
-
// 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.
|
|
1704
2278
|
ws.removeEventListener('open', onOpen);
|
|
1705
2279
|
ws.addEventListener('open', () => ws.close());
|
|
1706
|
-
// Some
|
|
1707
|
-
//
|
|
1708
|
-
//
|
|
1709
|
-
// 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.
|
|
1710
2283
|
const onOrphanError = () => undefined;
|
|
1711
2284
|
const onOrphanClose = () => {
|
|
1712
2285
|
ws.removeEventListener('error', onOrphanError);
|
|
@@ -1717,8 +2290,7 @@ function createWebSocket(wsUrl, timeoutMs = WS_TIMEOUT) {
|
|
|
1717
2290
|
ws.close();
|
|
1718
2291
|
}
|
|
1719
2292
|
else {
|
|
1720
|
-
//
|
|
1721
|
-
// Just remove our internal listener; don't touch the socket.
|
|
2293
|
+
// Delivered — the consumer owns it; only drop our listener.
|
|
1722
2294
|
ws.removeEventListener('open', onOpen);
|
|
1723
2295
|
}
|
|
1724
2296
|
};
|
|
@@ -2352,10 +2924,10 @@ class SignallingService extends SubService {
|
|
|
2352
2924
|
Logger.log('Start Getting Region');
|
|
2353
2925
|
return this.regionsPingService.getFastest().pipe(take(1));
|
|
2354
2926
|
}
|
|
2355
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
2356
|
-
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' }); }
|
|
2357
2929
|
}
|
|
2358
|
-
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: [{
|
|
2359
2931
|
type: Injectable,
|
|
2360
2932
|
args: [{ providedIn: 'root' }]
|
|
2361
2933
|
}], ctorParameters: () => [] });
|
|
@@ -2770,10 +3342,10 @@ class VideoService extends SubService {
|
|
|
2770
3342
|
this.armGestureRetry(audio);
|
|
2771
3343
|
}
|
|
2772
3344
|
}
|
|
2773
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
2774
|
-
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' }); }
|
|
2775
3347
|
}
|
|
2776
|
-
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: [{
|
|
2777
3349
|
type: Injectable,
|
|
2778
3350
|
args: [{ providedIn: 'root' }]
|
|
2779
3351
|
}], ctorParameters: () => [] });
|
|
@@ -3439,10 +4011,10 @@ class WebRtcPlayerService extends SubService {
|
|
|
3439
4011
|
Logger.error("Couldn't create answer", e);
|
|
3440
4012
|
}
|
|
3441
4013
|
}
|
|
3442
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
3443
|
-
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' }); }
|
|
3444
4016
|
}
|
|
3445
|
-
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: [{
|
|
3446
4018
|
type: Injectable,
|
|
3447
4019
|
args: [{ providedIn: 'root' }]
|
|
3448
4020
|
}], ctorParameters: () => [] });
|
|
@@ -3612,10 +4184,10 @@ class StreamAdoptionService {
|
|
|
3612
4184
|
this.webRtc.adopt(parked.pc, parked.dc, parked.stream, parked.config ?? {}, parked.dcBuffer);
|
|
3613
4185
|
return true;
|
|
3614
4186
|
}
|
|
3615
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
3616
|
-
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' }); }
|
|
3617
4189
|
}
|
|
3618
|
-
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: [{
|
|
3619
4191
|
type: Injectable,
|
|
3620
4192
|
args: [{ providedIn: 'root' }]
|
|
3621
4193
|
}] });
|
|
@@ -3683,10 +4255,10 @@ class UnrealCallbackService {
|
|
|
3683
4255
|
return observable;
|
|
3684
4256
|
});
|
|
3685
4257
|
}
|
|
3686
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
3687
|
-
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' }); }
|
|
3688
4260
|
}
|
|
3689
|
-
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: [{
|
|
3690
4262
|
type: Injectable,
|
|
3691
4263
|
args: [{ providedIn: 'root' }]
|
|
3692
4264
|
}] });
|
|
@@ -3803,10 +4375,10 @@ class UnrealCommunicatorService extends SubService {
|
|
|
3803
4375
|
requestQualityControl() {
|
|
3804
4376
|
this.sendInputData(new Uint8Array([MessageType.RequestQualityControl]).buffer);
|
|
3805
4377
|
}
|
|
3806
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
3807
|
-
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' }); }
|
|
3808
4380
|
}
|
|
3809
|
-
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: [{
|
|
3810
4382
|
type: Injectable,
|
|
3811
4383
|
args: [{ providedIn: 'root' }]
|
|
3812
4384
|
}], ctorParameters: () => [] });
|
|
@@ -3820,10 +4392,10 @@ class UnrealErrorModalComponent {
|
|
|
3820
4392
|
close() {
|
|
3821
4393
|
this.#dialogRef.close();
|
|
3822
4394
|
}
|
|
3823
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
3824
|
-
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 }); }
|
|
3825
4397
|
}
|
|
3826
|
-
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: [{
|
|
3827
4399
|
type: Component,
|
|
3828
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"] }]
|
|
3829
4401
|
}] });
|
|
@@ -4219,10 +4791,10 @@ class UnrealEffects {
|
|
|
4219
4791
|
// Fails silently if cross-origin
|
|
4220
4792
|
}
|
|
4221
4793
|
}
|
|
4222
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
4223
|
-
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 }); }
|
|
4224
4796
|
}
|
|
4225
|
-
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: [{
|
|
4226
4798
|
type: Injectable
|
|
4227
4799
|
}] });
|
|
4228
4800
|
|
|
@@ -4374,10 +4946,9 @@ const floatToSmoothPercents = () => (source) => source.pipe(timestamp(), startWi
|
|
|
4374
4946
|
* Smoothly interpolates from `start` to `end` over `duration`ms using the
|
|
4375
4947
|
* animation frame scheduler. Completes when the transition finishes.
|
|
4376
4948
|
*
|
|
4377
|
-
*
|
|
4378
|
-
*
|
|
4379
|
-
*
|
|
4380
|
-
* 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`.
|
|
4381
4952
|
*/
|
|
4382
4953
|
const smoothTransition = (start, end, duration) => {
|
|
4383
4954
|
const startTime = animationFrameScheduler.now();
|
|
@@ -4739,10 +5310,10 @@ class AFKService extends SubService {
|
|
|
4739
5310
|
}
|
|
4740
5311
|
}, 1000);
|
|
4741
5312
|
}
|
|
4742
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
4743
|
-
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' }); }
|
|
4744
5315
|
}
|
|
4745
|
-
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: [{
|
|
4746
5317
|
type: Injectable,
|
|
4747
5318
|
args: [{ providedIn: 'root' }]
|
|
4748
5319
|
}], ctorParameters: () => [] });
|
|
@@ -4792,10 +5363,10 @@ class LoadingProgressService {
|
|
|
4792
5363
|
// `switchMap` cancels the inner subscription on every visibility change
|
|
4793
5364
|
// so stale emissions can't leak through.
|
|
4794
5365
|
#boundedProgress$;
|
|
4795
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
4796
|
-
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' }); }
|
|
4797
5368
|
}
|
|
4798
|
-
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: [{
|
|
4799
5370
|
type: Injectable,
|
|
4800
5371
|
args: [{ providedIn: 'root' }]
|
|
4801
5372
|
}] });
|
|
@@ -4881,10 +5452,10 @@ class FreezeFrameService extends SubService {
|
|
|
4881
5452
|
progress: 1,
|
|
4882
5453
|
}));
|
|
4883
5454
|
}
|
|
4884
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
4885
|
-
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' }); }
|
|
4886
5457
|
}
|
|
4887
|
-
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: [{
|
|
4888
5459
|
type: Injectable,
|
|
4889
5460
|
args: [{ providedIn: 'root' }]
|
|
4890
5461
|
}], ctorParameters: () => [] });
|
|
@@ -5036,19 +5607,21 @@ class FileReceiverService extends SubService {
|
|
|
5036
5607
|
this.reset();
|
|
5037
5608
|
}
|
|
5038
5609
|
}
|
|
5039
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
5040
|
-
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' }); }
|
|
5041
5612
|
}
|
|
5042
|
-
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: [{
|
|
5043
5614
|
type: Injectable,
|
|
5044
5615
|
args: [{ providedIn: 'root' }]
|
|
5045
5616
|
}], ctorParameters: () => [] });
|
|
5046
5617
|
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
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));
|
|
5052
5625
|
class AggregatorService extends SubService {
|
|
5053
5626
|
constructor() {
|
|
5054
5627
|
super();
|
|
@@ -5135,7 +5708,11 @@ class AggregatorService extends SubService {
|
|
|
5135
5708
|
});
|
|
5136
5709
|
}
|
|
5137
5710
|
showMessageFromUnreal(json) {
|
|
5138
|
-
|
|
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))) {
|
|
5139
5716
|
return;
|
|
5140
5717
|
}
|
|
5141
5718
|
Logger.colored(...COLOR_CODES.FROM_UNREAL, json);
|
|
@@ -5218,10 +5795,10 @@ class AggregatorService extends SubService {
|
|
|
5218
5795
|
Logger.warn(`unrecognized data received, packet ID ${view[0]}`);
|
|
5219
5796
|
}
|
|
5220
5797
|
}
|
|
5221
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
5222
|
-
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' }); }
|
|
5223
5800
|
}
|
|
5224
|
-
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: [{
|
|
5225
5802
|
type: Injectable,
|
|
5226
5803
|
args: [{ providedIn: 'root' }]
|
|
5227
5804
|
}], ctorParameters: () => [] });
|
|
@@ -5382,10 +5959,10 @@ class ConsoleExtensionsService extends SubService {
|
|
|
5382
5959
|
Logger.info('emitCommand(command) => send command to Unreal Engine.');
|
|
5383
5960
|
Logger.info('stressTest({iterations}) => hammer reconnect: repeatedly drop DC/PC and assert recovery.');
|
|
5384
5961
|
}
|
|
5385
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
5386
|
-
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' }); }
|
|
5387
5964
|
}
|
|
5388
|
-
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: [{
|
|
5389
5966
|
type: Injectable,
|
|
5390
5967
|
args: [{ providedIn: 'root' }]
|
|
5391
5968
|
}], ctorParameters: () => [] });
|
|
@@ -5399,30 +5976,48 @@ const RESIZE_DEBOUNCE_MS = 300;
|
|
|
5399
5976
|
const FUNCTION_KEY_MIN = 112;
|
|
5400
5977
|
const FUNCTION_KEY_MAX = 123;
|
|
5401
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"])';
|
|
5402
5985
|
class InputService extends SubService {
|
|
5403
5986
|
constructor() {
|
|
5404
5987
|
super();
|
|
5405
5988
|
this.commandsSender = inject(UnrealCommunicatorService);
|
|
5406
|
-
|
|
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);
|
|
5407
5992
|
this.videoService = inject(VideoService);
|
|
5408
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`.
|
|
5409
5999
|
this.defaultKeys = [
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
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',
|
|
5424
6019
|
];
|
|
5425
|
-
this.availableKeys = this.defaultKeys;
|
|
6020
|
+
this.availableKeys = new Set(this.defaultKeys);
|
|
5426
6021
|
this.options = InputOptions;
|
|
5427
6022
|
this.reInit$ = new Subject();
|
|
5428
6023
|
this.deactivatedVideoTrigger$ = NEVER;
|
|
@@ -5439,6 +6034,12 @@ class InputService extends SubService {
|
|
|
5439
6034
|
this.fingerIds = new Map();
|
|
5440
6035
|
this.maxByteValue = 255;
|
|
5441
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();
|
|
5442
6043
|
// Reusable wire buffers. Input events fire at up to ~60 Hz; the data channel
|
|
5443
6044
|
// copies the bytes synchronously on sending (RTCDataChannel.send), so a single
|
|
5444
6045
|
// buffer per message shape is safe and avoids per-event allocation/GC churn.
|
|
@@ -5471,8 +6072,17 @@ class InputService extends SubService {
|
|
|
5471
6072
|
.pipe(filter(() => !!this.video), takeUntil$1(this.destroy$))
|
|
5472
6073
|
.subscribe(() => this.setup());
|
|
5473
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
|
+
*/
|
|
5474
6084
|
useKeyboardKeys(keys) {
|
|
5475
|
-
this.availableKeys = keys;
|
|
6085
|
+
this.availableKeys = new Set(keys.map((key) => (typeof key === 'number' ? InvertedKeyMap[key] : key)));
|
|
5476
6086
|
}
|
|
5477
6087
|
get video() {
|
|
5478
6088
|
return this.videoService.video;
|
|
@@ -5487,6 +6097,10 @@ class InputService extends SubService {
|
|
|
5487
6097
|
// Reset touch state to prevent stale identifiers across sessions
|
|
5488
6098
|
this.fingerIds.clear();
|
|
5489
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();
|
|
5490
6104
|
merge(fromResizeObserver(video), this.actions$.pipe(ofType(videoAdaptedToContainer)))
|
|
5491
6105
|
.pipe(debounceTime$1(RESIZE_DEBOUNCE_MS), takeUntil$1(this.deactivatedVideoTrigger$))
|
|
5492
6106
|
.subscribe(() => this.setupNormalizeAndQuantize(video));
|
|
@@ -5574,9 +6188,17 @@ class InputService extends SubService {
|
|
|
5574
6188
|
fromEvent(window, 'blur')
|
|
5575
6189
|
.pipe(filter(() => !!video), takeUntil$1(this.deactivatedVideoTrigger$))
|
|
5576
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());
|
|
5577
6199
|
this.registerMouseEnterAndLeaveEvents(video);
|
|
5578
6200
|
this.registerHoveringMouseEvents(video);
|
|
5579
|
-
this.registerKeyboardEvents(
|
|
6201
|
+
this.registerKeyboardEvents();
|
|
5580
6202
|
this.registerTouchEvents(video);
|
|
5581
6203
|
}
|
|
5582
6204
|
getTouchPositionWithOffset({ clientX, clientY }) {
|
|
@@ -5798,62 +6420,108 @@ class InputService extends SubService {
|
|
|
5798
6420
|
this.releaseMouseButtons(e.buttons, e.offsetX, e.offsetY);
|
|
5799
6421
|
});
|
|
5800
6422
|
}
|
|
5801
|
-
|
|
5802
|
-
|
|
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) {
|
|
5803
6432
|
return ((keyCode >= FUNCTION_KEY_MIN && keyCode <= FUNCTION_KEY_MAX) ||
|
|
6433
|
+
(keyCode >= ARROW_KEY_MIN && keyCode <= ARROW_KEY_MAX) ||
|
|
5804
6434
|
keyCode === TAB_KEY_CODE);
|
|
5805
6435
|
}
|
|
5806
6436
|
/**
|
|
5807
|
-
* 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.
|
|
5808
6439
|
*
|
|
5809
|
-
* `
|
|
5810
|
-
*
|
|
5811
|
-
*
|
|
5812
|
-
* `KeyboardNumericCode` is keyed by `e.code` and holds the virtual-key value,
|
|
5813
|
-
* 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.
|
|
5814
6443
|
*
|
|
5815
|
-
*
|
|
5816
|
-
*
|
|
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.
|
|
5817
6447
|
*/
|
|
5818
6448
|
getKeyCode(e) {
|
|
5819
|
-
if (e.keyCode ===
|
|
5820
|
-
return
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5826
|
-
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
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;
|
|
5841
6479
|
}
|
|
5842
|
-
|
|
5843
|
-
const
|
|
6480
|
+
sendKeyUp(keyCode) {
|
|
6481
|
+
const keyUp = this.keyUpBytes;
|
|
6482
|
+
keyUp[0] = MessageType.KeyUp;
|
|
6483
|
+
keyUp[1] = keyCode;
|
|
6484
|
+
this.sendInputData(keyUp.buffer);
|
|
6485
|
+
}
|
|
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() {
|
|
5844
6499
|
fromEvent(document, 'keydown')
|
|
5845
6500
|
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
5846
6501
|
.subscribe((e) => {
|
|
5847
|
-
|
|
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)) {
|
|
5848
6505
|
return;
|
|
5849
6506
|
}
|
|
5850
|
-
const isCtrlOrCommand = e.ctrlKey || e.metaKey;
|
|
5851
|
-
// Normalised first: on Firefox the raw `e.keyCode` for these keys is 61
|
|
5852
|
-
// and 173, so comparing it left browser zoom to reach the engine too.
|
|
5853
6507
|
const keyCode = this.getKeyCode(e);
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
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)) {
|
|
5857
6525
|
return;
|
|
5858
6526
|
}
|
|
5859
6527
|
const keyDown = this.keyDownBytes;
|
|
@@ -5861,38 +6529,46 @@ class InputService extends SubService {
|
|
|
5861
6529
|
keyDown[1] = keyCode;
|
|
5862
6530
|
keyDown[2] = Number(e.repeat);
|
|
5863
6531
|
this.sendInputData(keyDown.buffer);
|
|
6532
|
+
this.heldKeys.add(keyCode);
|
|
5864
6533
|
// Backspace isn't a keypress in JS, but UE4 text-entry fields need it
|
|
5865
6534
|
// to delete characters.
|
|
5866
|
-
if (
|
|
6535
|
+
if (keyCode === SpecialKeyCodes.BackSpace) {
|
|
5867
6536
|
const data = this.keyPressView;
|
|
5868
6537
|
data.setUint8(0, MessageType.KeyPress);
|
|
5869
6538
|
data.setUint16(1, SpecialKeyCodes.BackSpace, true);
|
|
5870
6539
|
this.sendInputData(data.buffer);
|
|
5871
6540
|
}
|
|
5872
|
-
if (this.options.suppressBrowserKeys &&
|
|
5873
|
-
this.isKeyCodeBrowserKey(e.keyCode)) {
|
|
5874
|
-
e.preventDefault();
|
|
5875
|
-
}
|
|
5876
6541
|
});
|
|
5877
6542
|
fromEvent(document, 'keyup')
|
|
5878
6543
|
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
5879
6544
|
.subscribe((e) => {
|
|
5880
|
-
|
|
6545
|
+
const keyCode = this.getKeyCode(e);
|
|
6546
|
+
if (keyCode === null) {
|
|
5881
6547
|
return;
|
|
5882
6548
|
}
|
|
5883
|
-
const keyUp = this.keyUpBytes;
|
|
5884
|
-
keyUp[0] = MessageType.KeyUp;
|
|
5885
|
-
keyUp[1] = this.getKeyCode(e);
|
|
5886
|
-
this.sendInputData(keyUp.buffer);
|
|
5887
6549
|
if (this.options.suppressBrowserKeys &&
|
|
5888
|
-
this.
|
|
6550
|
+
this.isBrowserKey(keyCode) &&
|
|
6551
|
+
!this.isTextEntryTarget(e)) {
|
|
5889
6552
|
e.preventDefault();
|
|
5890
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);
|
|
5891
6562
|
});
|
|
5892
6563
|
fromEvent(document, 'keypress')
|
|
5893
6564
|
.pipe(takeUntil$1(this.deactivatedVideoTrigger$))
|
|
5894
6565
|
.subscribe((e) => {
|
|
5895
|
-
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) {
|
|
5896
6572
|
return;
|
|
5897
6573
|
}
|
|
5898
6574
|
const data = this.keyPressView;
|
|
@@ -5901,10 +6577,10 @@ class InputService extends SubService {
|
|
|
5901
6577
|
this.sendInputData(data.buffer);
|
|
5902
6578
|
});
|
|
5903
6579
|
}
|
|
5904
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
5905
|
-
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' }); }
|
|
5906
6582
|
}
|
|
5907
|
-
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: [{
|
|
5908
6584
|
type: Injectable,
|
|
5909
6585
|
args: [{ providedIn: 'root' }]
|
|
5910
6586
|
}], ctorParameters: () => [] });
|
|
@@ -5973,46 +6649,36 @@ class StreamStatusTelemetryService extends SubService {
|
|
|
5973
6649
|
VideoEncoderQP,
|
|
5974
6650
|
};
|
|
5975
6651
|
}
|
|
5976
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
5977
|
-
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' }); }
|
|
5978
6654
|
}
|
|
5979
|
-
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: [{
|
|
5980
6656
|
type: Injectable,
|
|
5981
6657
|
args: [{ providedIn: 'root' }]
|
|
5982
6658
|
}], ctorParameters: () => [] });
|
|
5983
6659
|
|
|
5984
6660
|
/**
|
|
5985
|
-
*
|
|
6661
|
+
* Telemetry for the WebRTC stream lifecycle.
|
|
5986
6662
|
*
|
|
5987
|
-
*
|
|
5988
|
-
*
|
|
5989
|
-
*
|
|
5990
|
-
*
|
|
5991
|
-
*
|
|
5992
|
-
*
|
|
5993
|
-
*
|
|
5994
|
-
*
|
|
5995
|
-
* - `stream.quality_degraded` — on QP entering `red` (>35)
|
|
5996
|
-
* - `stream.quality_recovered` — on QP leaving `red`
|
|
5997
|
-
* - `stream.fps_low` — when the window FPS p50 < 70% of the target
|
|
5998
|
-
* - `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.
|
|
5999
6671
|
*
|
|
6000
|
-
*
|
|
6001
|
-
*
|
|
6002
|
-
*
|
|
6003
|
-
*
|
|
6004
|
-
* 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
|
|
6005
6676
|
* {@link SessionState.wireId}); a session that never got one falls back to a
|
|
6006
|
-
*
|
|
6007
|
-
*
|
|
6008
|
-
* 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.
|
|
6009
6679
|
*
|
|
6010
|
-
* NOTE:
|
|
6011
|
-
*
|
|
6012
|
-
*
|
|
6013
|
-
* Every wire shape lives in `interfaces/stream-telemetry-events.interface.ts`
|
|
6014
|
-
* — `track()` / `emitLifecycle()` are typed against it, so a payload that
|
|
6015
|
-
* 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'`.
|
|
6016
6682
|
*/
|
|
6017
6683
|
/** Trim a resource URL to its path: drop origin and query string so the
|
|
6018
6684
|
* emitted name is short, stable, and not a PII-bearing query. */
|
|
@@ -6337,45 +7003,31 @@ class StreamStatusTelemetryService2 {
|
|
|
6337
7003
|
}
|
|
6338
7004
|
}
|
|
6339
7005
|
init() {
|
|
6340
|
-
//
|
|
6341
|
-
//
|
|
6342
|
-
//
|
|
6343
|
-
//
|
|
6344
|
-
//
|
|
6345
|
-
//
|
|
6346
|
-
// per real attempt
|
|
6347
|
-
//
|
|
6348
|
-
// (prefetch adoption / fresh connect). So binding here yields one session
|
|
6349
|
-
// per attempt instead of a burst of `restart` churn sessions. Genuine
|
|
6350
|
-
// reconnects (e.g. DataChannelTimeout) re-enter the same path and
|
|
6351
|
-
// 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`.
|
|
6352
7014
|
//
|
|
6353
|
-
// Do NOT add a second dispatch site:
|
|
6354
|
-
// `
|
|
6355
|
-
//
|
|
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.
|
|
6356
7018
|
this.actions$
|
|
6357
7019
|
.pipe(ofType(setEstablishingConnection), filter$1(({ value }) => value === true), takeUntil$1(this.destroy$))
|
|
6358
7020
|
.subscribe(() => this.startSession());
|
|
6359
|
-
//
|
|
6360
|
-
//
|
|
6361
|
-
//
|
|
6362
|
-
//
|
|
6363
|
-
//
|
|
6364
|
-
//
|
|
6365
|
-
// `
|
|
6366
|
-
// synchronously inside that reducer's emission, before the
|
|
6367
|
-
// follow-up effect (`destroyUnrealScene → destroyRemoteConnections({Destroy})`)
|
|
6368
|
-
// gets a chance to write `Destroy` back into state — so the
|
|
6369
|
-
// subscriber would see `None` and end as `'disconnected'`.
|
|
6370
|
-
//
|
|
6371
|
-
// Subscribing to the actions instead lets us pick the right
|
|
6372
|
-
// reason per dispatched action, and `endSession` is idempotent
|
|
6373
|
-
// (`if (!this.session) return`) so any cascading second trigger
|
|
6374
|
-
// 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:
|
|
6375
7028
|
// - `destroyUnrealScene` → `'destroy'` (route change, removed from DOM)
|
|
6376
|
-
// - `setCirrusDisconnected` → `'disconnected'` (WS close, AFK,
|
|
6377
|
-
//
|
|
6378
|
-
// read from current state in `endSession`)
|
|
7029
|
+
// - `setCirrusDisconnected` → `'disconnected'` (WS close, AFK, manual
|
|
7030
|
+
// drop, WebRTCError — granular cause read from state in `endSession`)
|
|
6379
7031
|
this.actions$
|
|
6380
7032
|
.pipe(ofType(destroyUnrealScene), takeUntil$1(this.destroy$))
|
|
6381
7033
|
.subscribe(() => this.endSession('destroy'));
|
|
@@ -6671,11 +7323,10 @@ class StreamStatusTelemetryService2 {
|
|
|
6671
7323
|
/**
|
|
6672
7324
|
* Emit the region / signaling / webrtc phases for an ADOPTED connection.
|
|
6673
7325
|
*
|
|
6674
|
-
* The prefetch script established the connection in
|
|
6675
|
-
* so
|
|
6676
|
-
*
|
|
6677
|
-
*
|
|
6678
|
-
* 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:
|
|
6679
7330
|
* - `duration` — the real sub-step time the prefetch spent.
|
|
6680
7331
|
* - `spanStartMs` — anchor-relative start, so the viewer left-shifts the bar.
|
|
6681
7332
|
* - `adoptionAtMs` — where Angular took over (the next phase, Unreal
|
|
@@ -6941,22 +7592,15 @@ class StreamStatusTelemetryService2 {
|
|
|
6941
7592
|
}
|
|
6942
7593
|
}
|
|
6943
7594
|
/**
|
|
6944
|
-
*
|
|
6945
|
-
*
|
|
6946
|
-
*
|
|
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.
|
|
6947
7601
|
*
|
|
6948
|
-
*
|
|
6949
|
-
*
|
|
6950
|
-
* - `lazyResources` — fetched after `loadEventEnd` (= typically the
|
|
6951
|
-
* route's lazy-loaded chunks, JSON manifests etc. that download
|
|
6952
|
-
* when the user navigates to a sub-route the streamer lives on).
|
|
6953
|
-
*
|
|
6954
|
-
* When `loadEventEnd` is 0/unknown, everything goes into `resources`
|
|
6955
|
-
* and `lazyResources` is null — old behavior.
|
|
6956
|
-
*
|
|
6957
|
-
* `transferSize === 0 && decodedBodySize > 0` means the resource came from
|
|
6958
|
-
* the HTTP cache — counted separately so cached hits don't inflate
|
|
6959
|
-
* 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.
|
|
6960
7604
|
*/
|
|
6961
7605
|
collectResourceTotals(loadEventEnd) {
|
|
6962
7606
|
try {
|
|
@@ -7078,10 +7722,10 @@ class StreamStatusTelemetryService2 {
|
|
|
7078
7722
|
emit(event, data) {
|
|
7079
7723
|
this.store.dispatch(trackTelemetryData({ event, data }));
|
|
7080
7724
|
}
|
|
7081
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7082
|
-
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' }); }
|
|
7083
7727
|
}
|
|
7084
|
-
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: [{
|
|
7085
7729
|
type: Injectable,
|
|
7086
7730
|
args: [{ providedIn: 'root' }]
|
|
7087
7731
|
}], ctorParameters: () => [] });
|
|
@@ -7167,10 +7811,10 @@ class FileHandlerService {
|
|
|
7167
7811
|
return observable;
|
|
7168
7812
|
});
|
|
7169
7813
|
}
|
|
7170
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7171
|
-
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' }); }
|
|
7172
7816
|
}
|
|
7173
|
-
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: [{
|
|
7174
7818
|
type: Injectable,
|
|
7175
7819
|
args: [{ providedIn: 'root' }]
|
|
7176
7820
|
}] });
|
|
@@ -7259,86 +7903,31 @@ class AnalyticsService extends SubService {
|
|
|
7259
7903
|
Logger.log('Analytics Event:', name, params);
|
|
7260
7904
|
this.store.dispatch(saveAnalyticsEvent({ event: { name, params } }));
|
|
7261
7905
|
}
|
|
7262
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7263
|
-
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' }); }
|
|
7264
7908
|
}
|
|
7265
|
-
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: [{
|
|
7266
7910
|
type: Injectable,
|
|
7267
7911
|
args: [{ providedIn: 'root' }]
|
|
7268
7912
|
}], ctorParameters: () => [] });
|
|
7269
7913
|
|
|
7270
7914
|
/**
|
|
7271
|
-
* Adaptive FPS controller
|
|
7272
|
-
*
|
|
7273
|
-
*
|
|
7274
|
-
* ## How it works
|
|
7275
|
-
*
|
|
7276
|
-
* The service subscribes to `VideoService.videoStats$` (emitted every 250 ms)
|
|
7277
|
-
* and collects samples of FPS, bitrate, and QP (Quantization Parameter).
|
|
7278
|
-
* Every {@link SAMPLE_WINDOW} ticks (~2 s) it averages the collected samples
|
|
7279
|
-
* and feeds them into a set of **fuzzy-logic membership functions** that
|
|
7280
|
-
* classify each metric into overlapping quality bands.
|
|
7281
|
-
*
|
|
7282
|
-
* ### Input signals
|
|
7283
|
-
*
|
|
7284
|
-
* **1. FPS ratio** = `actualFPS / currentTargetFPS` (0..1+)
|
|
7285
|
-
*
|
|
7286
|
-
* | Band | Range | Meaning |
|
|
7287
|
-
* |--------|---------------------|-----------------------------------------------|
|
|
7288
|
-
* | low | ratio < 0.7 → 1.0, linear ramp 0.7..0.9 → 0 | Stream cannot keep up with the target |
|
|
7289
|
-
* | okays | triangle 0.8..1.0, peak at 0.95 | Stream roughly matches the target |
|
|
7290
|
-
* | 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}.
|
|
7291
7917
|
*
|
|
7292
|
-
*
|
|
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.
|
|
7293
7922
|
*
|
|
7294
|
-
*
|
|
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.
|
|
7295
7927
|
*
|
|
7296
|
-
*
|
|
7297
|
-
*
|
|
7298
|
-
*
|
|
7299
|
-
* | not high | load < 0.5 → 0.0 | Bandwidth headroom is available |
|
|
7300
|
-
*
|
|
7301
|
-
* **3. Quality** — mapped from QP via `mapQpToQuality()` (see {@link Quality}):
|
|
7302
|
-
*
|
|
7303
|
-
* | Quality | QP range | Meaning |
|
|
7304
|
-
* |----------|-----------|-------------------------------------------------|
|
|
7305
|
-
* | `lime` | QP <= 26 | Good — encoder has enough headroom |
|
|
7306
|
-
* | `orange` | QP 27..35 | Fair — encoder is under moderate pressure |
|
|
7307
|
-
* | `red` | QP > 35 | Poor — heavy compression, visible artifacts |
|
|
7308
|
-
*
|
|
7309
|
-
* ### Decision rules (evaluated in priority order, first match wins)
|
|
7310
|
-
*
|
|
7311
|
-
* | # | Condition | Decision |
|
|
7312
|
-
* |---|------------------------------------------------------------|--------------|
|
|
7313
|
-
* | 1 | FPS ratio is **low** (membership > 0.5) | **decrease** |
|
|
7314
|
-
* | 2 | FPS ratio is **ok** AND quality is `red` | **decrease** |
|
|
7315
|
-
* | 3 | FPS ratio is **ok** AND bitrate **high** AND quality is `orange` | **hold** |
|
|
7316
|
-
* | 4 | FPS ratio is **high** AND quality is `lime` AND bitrate **not high** | **increase** |
|
|
7317
|
-
* | — | Everything else | **hold** |
|
|
7318
|
-
*
|
|
7319
|
-
* ## Cooldown-based throttling
|
|
7320
|
-
*
|
|
7321
|
-
* The service continuously evaluates fuzzy rules in every sample window.
|
|
7322
|
-
* After each FPS step change it enforces a cooldown before the next
|
|
7323
|
-
* change can be applied. The cooldown duration depends on the
|
|
7324
|
-
* (previous decision → next decision) pair:
|
|
7325
|
-
*
|
|
7326
|
-
* | Previous | Next | Cooldown |
|
|
7327
|
-
* |-----------|-----------|-----------------------------------------------------|
|
|
7328
|
-
* | decrease | decrease | {@link COOLDOWN_DECREASE_AFTER_DECREASE_MS} (2 s) |
|
|
7329
|
-
* | decrease | increase | {@link COOLDOWN_INCREASE_AFTER_DECREASE_MS} (10 s) |
|
|
7330
|
-
* | increase | decrease | {@link COOLDOWN_AFTER_INCREASE_MS} (2 s) |
|
|
7331
|
-
* | increase | increase | {@link COOLDOWN_AFTER_INCREASE_MS} (2 s) |
|
|
7332
|
-
*
|
|
7333
|
-
* This means the system reacts quickly after an increase (2 s in any
|
|
7334
|
-
* direction) but is cautious about stepping back up after a decrease
|
|
7335
|
-
* (10 s), while still allowing consecutive decreases at 2 s intervals.
|
|
7336
|
-
*
|
|
7337
|
-
* ## FPS dispatch
|
|
7338
|
-
*
|
|
7339
|
-
* FPS changes are dispatched via the NgRx `setMaxFps` action, which triggers
|
|
7340
|
-
* the existing `UnrealEffects.setMaxFps$` effect that sends the
|
|
7341
|
-
* `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.
|
|
7342
7931
|
*/
|
|
7343
7932
|
class FpsMonitorService extends SubService {
|
|
7344
7933
|
constructor() {
|
|
@@ -7439,15 +8028,7 @@ class FpsMonitorService extends SubService {
|
|
|
7439
8028
|
const decision = this.evaluateDecision(avg, currentTarget);
|
|
7440
8029
|
this.upgradeFps(decision, avg.qp);
|
|
7441
8030
|
}
|
|
7442
|
-
/**
|
|
7443
|
-
* Combines fuzzy membership values into a single discrete decision.
|
|
7444
|
-
* Rules are evaluated in priority order — first match wins.
|
|
7445
|
-
*
|
|
7446
|
-
* Inputs:
|
|
7447
|
-
* - `fpsRatio` = avgFPS / currentTargetFPS (e.g., 45/60 = 0.75)
|
|
7448
|
-
* - `bitrateLoad` = avgBitrate / 20 Mbit/s (e.g., 12M/20M = 0.6)
|
|
7449
|
-
* - `quality` = mapQpToQuality(avgQP) → 'lime' | 'orange' | 'red'
|
|
7450
|
-
*/
|
|
8031
|
+
/** Rules are evaluated in priority order — first match wins. */
|
|
7451
8032
|
evaluateDecision(avg, currentTarget) {
|
|
7452
8033
|
const referenceTarget = currentTarget > 0 ? currentTarget : this.UNLIMITED_REFERENCE_FPS;
|
|
7453
8034
|
const fpsRatio = avg.fps / referenceTarget;
|
|
@@ -7487,21 +8068,10 @@ class FpsMonitorService extends SubService {
|
|
|
7487
8068
|
}
|
|
7488
8069
|
return 'hold';
|
|
7489
8070
|
}
|
|
7490
|
-
//
|
|
7491
|
-
//
|
|
7492
|
-
//
|
|
7493
|
-
|
|
7494
|
-
// Overlapping trapezoid/triangle shapes let multiple categories be partially
|
|
7495
|
-
// active at the same time, which makes the rules less brittle than hard thresholds.
|
|
7496
|
-
// ---------------------------------------------------------------------------
|
|
7497
|
-
/**
|
|
7498
|
-
* FPS ratio membership "low".
|
|
7499
|
-
* Input: a ratio = actualFPS / targetFPS (e.g., 42/60 = 0.70).
|
|
7500
|
-
*
|
|
7501
|
-
* ratio < 0.7 → 1.0 (clearly failing, e.g., 40/60)
|
|
7502
|
-
* ratio 0.7..0.9 → linear ramp down (e.g., 0.8 → 0.5)
|
|
7503
|
-
* a ratio > 0.9 → 0.0 (keeping up)
|
|
7504
|
-
*/
|
|
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. */
|
|
7505
8075
|
membershipFpsLow(ratio) {
|
|
7506
8076
|
if (ratio < 0.7)
|
|
7507
8077
|
return 1.0;
|
|
@@ -7509,15 +8079,7 @@ class FpsMonitorService extends SubService {
|
|
|
7509
8079
|
return 0.0;
|
|
7510
8080
|
return (0.9 - ratio) / 0.2;
|
|
7511
8081
|
}
|
|
7512
|
-
/**
|
|
7513
|
-
* FPS ratio membership "ok" — triangle shape.
|
|
7514
|
-
* Input: ratio = actualFPS / targetFPS.
|
|
7515
|
-
*
|
|
7516
|
-
* ratio < 0.8 → 0.0
|
|
7517
|
-
* ratio 0.8..0.95 → ramp up, peak at 0.95 (e.g., 57/60)
|
|
7518
|
-
* ratio 0.95..1.0 → ramp down
|
|
7519
|
-
* a ratio > 1.0 → 0.0
|
|
7520
|
-
*/
|
|
8082
|
+
/** "ok" — triangle peaking just under the target. */
|
|
7521
8083
|
membershipFpsOk(ratio) {
|
|
7522
8084
|
if (ratio < 0.8)
|
|
7523
8085
|
return 0.0;
|
|
@@ -7527,14 +8089,7 @@ class FpsMonitorService extends SubService {
|
|
|
7527
8089
|
return (1.0 - ratio) / 0.05;
|
|
7528
8090
|
return 0.0;
|
|
7529
8091
|
}
|
|
7530
|
-
/**
|
|
7531
|
-
* FPS ratio membership "high".
|
|
7532
|
-
* Input: ratio = actualFPS / targetFPS.
|
|
7533
|
-
*
|
|
7534
|
-
* ratio < 0.9 → 0.0
|
|
7535
|
-
* ratio 0.9..1.0 → linear ramp up (e.g., 0.95 → 0.5)
|
|
7536
|
-
* a ratio >= 1.0 → 1.0 (meeting or exceeding target, e.g., 60/60)
|
|
7537
|
-
*/
|
|
8092
|
+
/** "high" — the stream meets or exceeds its target. */
|
|
7538
8093
|
membershipFpsHigh(ratio) {
|
|
7539
8094
|
if (ratio < 0.9)
|
|
7540
8095
|
return 0.0;
|
|
@@ -7542,14 +8097,7 @@ class FpsMonitorService extends SubService {
|
|
|
7542
8097
|
return 1.0;
|
|
7543
8098
|
return (ratio - 0.9) / 0.1;
|
|
7544
8099
|
}
|
|
7545
|
-
/**
|
|
7546
|
-
* Bitrate load membership "high".
|
|
7547
|
-
* Input: a load = currentBitrate / MAX_BITRATE (20 Mbit/s).
|
|
7548
|
-
*
|
|
7549
|
-
* load < 0.5 → 0.0 (below 10 Mbit/s — plenty of headroom)
|
|
7550
|
-
* load 0.5..0.8 → linear ramp (e.g., 13M/20M = 0.65 → 0.5)
|
|
7551
|
-
* load > 0.8 → 1.0 (above 16 Mbit/s — near capacity)
|
|
7552
|
-
*/
|
|
8100
|
+
/** "high" — the encoder is using most of the available bandwidth. */
|
|
7553
8101
|
membershipBitrateHigh(load) {
|
|
7554
8102
|
if (load < 0.5)
|
|
7555
8103
|
return 0.0;
|
|
@@ -7629,10 +8177,10 @@ class FpsMonitorService extends SubService {
|
|
|
7629
8177
|
}
|
|
7630
8178
|
return { fps: fps / len, bitrate: bitrate / len, qp: qp / len };
|
|
7631
8179
|
}
|
|
7632
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7633
|
-
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' }); }
|
|
7634
8182
|
}
|
|
7635
|
-
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: [{
|
|
7636
8184
|
type: Injectable,
|
|
7637
8185
|
args: [{ providedIn: 'root' }]
|
|
7638
8186
|
}], ctorParameters: () => [] });
|
|
@@ -7667,10 +8215,10 @@ class AfkTimeoutModalComponent {
|
|
|
7667
8215
|
resetAfk() {
|
|
7668
8216
|
this.#afkService.reset();
|
|
7669
8217
|
}
|
|
7670
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7671
|
-
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 }); }
|
|
7672
8220
|
}
|
|
7673
|
-
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: [{
|
|
7674
8222
|
type: Component,
|
|
7675
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"] }]
|
|
7676
8224
|
}], propDecorators: { uiClasses: [{ type: i0.Input, args: [{ isSignal: true, alias: "uiClasses", required: false }] }], contentTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentTemplate", required: false }] }] } });
|
|
@@ -7682,10 +8230,10 @@ class FreezeFrameComponent {
|
|
|
7682
8230
|
this.combinedFreeze = this.#store.selectSignal(selectFreezeFrameCombinedDataUrl);
|
|
7683
8231
|
}
|
|
7684
8232
|
#store;
|
|
7685
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7686
|
-
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 }); }
|
|
7687
8235
|
}
|
|
7688
|
-
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: [{
|
|
7689
8237
|
type: Component,
|
|
7690
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"] }]
|
|
7691
8239
|
}] });
|
|
@@ -7700,10 +8248,10 @@ class ImageLoadingSrcComponent {
|
|
|
7700
8248
|
loadingImageError() {
|
|
7701
8249
|
this.#store.dispatch(setLoadingImageSrc({ src: '' }));
|
|
7702
8250
|
}
|
|
7703
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7704
|
-
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 }); }
|
|
7705
8253
|
}
|
|
7706
|
-
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: [{
|
|
7707
8255
|
type: Component,
|
|
7708
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"] }]
|
|
7709
8257
|
}] });
|
|
@@ -7786,10 +8334,10 @@ class StatGraphComponent {
|
|
|
7786
8334
|
}
|
|
7787
8335
|
this.draw();
|
|
7788
8336
|
}
|
|
7789
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7790
|
-
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 }); }
|
|
7791
8339
|
}
|
|
7792
|
-
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: [{
|
|
7793
8341
|
type: Component,
|
|
7794
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"] }]
|
|
7795
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: [{
|
|
@@ -7804,10 +8352,10 @@ class UnrealResumeSlotDirective {
|
|
|
7804
8352
|
static ngTemplateContextGuard(_dir, _ctx) {
|
|
7805
8353
|
return true;
|
|
7806
8354
|
}
|
|
7807
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7808
|
-
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 }); }
|
|
7809
8357
|
}
|
|
7810
|
-
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: [{
|
|
7811
8359
|
type: Directive,
|
|
7812
8360
|
args: [{ selector: 'ng-template[unrealResumeSlot]' }]
|
|
7813
8361
|
}] });
|
|
@@ -7818,10 +8366,10 @@ class UnrealAfkSlotDirective {
|
|
|
7818
8366
|
static ngTemplateContextGuard(_dir, _ctx) {
|
|
7819
8367
|
return true;
|
|
7820
8368
|
}
|
|
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.
|
|
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 }); }
|
|
7823
8371
|
}
|
|
7824
|
-
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: [{
|
|
7825
8373
|
type: Directive,
|
|
7826
8374
|
args: [{ selector: 'ng-template[unrealAfkSlot]' }]
|
|
7827
8375
|
}] });
|
|
@@ -7832,10 +8380,10 @@ class UnrealStatusSlotDirective {
|
|
|
7832
8380
|
static ngTemplateContextGuard(_dir, _ctx) {
|
|
7833
8381
|
return true;
|
|
7834
8382
|
}
|
|
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.
|
|
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 }); }
|
|
7837
8385
|
}
|
|
7838
|
-
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: [{
|
|
7839
8387
|
type: Directive,
|
|
7840
8388
|
args: [{ selector: 'ng-template[unrealStatusSlot]' }]
|
|
7841
8389
|
}] });
|
|
@@ -7858,10 +8406,10 @@ class UnrealSpinnerComponent {
|
|
|
7858
8406
|
this.viewBox = computed(() => `0 0 ${this.size()} ${this.size()}`, /* @ts-ignore */
|
|
7859
8407
|
...(ngDevMode ? [{ debugName: "viewBox" }] : /* istanbul ignore next */ []));
|
|
7860
8408
|
}
|
|
7861
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7862
|
-
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 }); }
|
|
7863
8411
|
}
|
|
7864
|
-
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: [{
|
|
7865
8413
|
type: Component,
|
|
7866
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"] }]
|
|
7867
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 }] }] } });
|
|
@@ -7892,10 +8440,10 @@ class UnrealStatusComponent {
|
|
|
7892
8440
|
}
|
|
7893
8441
|
#store;
|
|
7894
8442
|
#loadingProgress;
|
|
7895
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7896
|
-
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 }); }
|
|
7897
8445
|
}
|
|
7898
|
-
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: [{
|
|
7899
8447
|
type: Component,
|
|
7900
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"] }]
|
|
7901
8449
|
}], propDecorators: { uiClasses: [{ type: i0.Input, args: [{ isSignal: true, alias: "uiClasses", required: false }] }], contentTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentTemplate", required: false }] }] } });
|
|
@@ -7928,10 +8476,10 @@ class SafePipe {
|
|
|
7928
8476
|
// content instead of disabling framework security checks.
|
|
7929
8477
|
return (this.sanitizer.sanitize(context, value) ?? '');
|
|
7930
8478
|
}
|
|
7931
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
7932
|
-
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" }); }
|
|
7933
8481
|
}
|
|
7934
|
-
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: [{
|
|
7935
8483
|
type: Pipe,
|
|
7936
8484
|
args: [{
|
|
7937
8485
|
name: 'safe',
|
|
@@ -8044,10 +8592,10 @@ class VideoStatsComponent {
|
|
|
8044
8592
|
elements: this.elementsToShow(),
|
|
8045
8593
|
}));
|
|
8046
8594
|
}
|
|
8047
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
8048
|
-
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 }); }
|
|
8049
8597
|
}
|
|
8050
|
-
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: [{
|
|
8051
8599
|
type: Component,
|
|
8052
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"] }]
|
|
8053
8601
|
}], ctorParameters: () => [] });
|
|
@@ -8109,10 +8657,10 @@ class ResumeStreamButtonComponent {
|
|
|
8109
8657
|
disconnect() {
|
|
8110
8658
|
this.isSecondStart.set(true);
|
|
8111
8659
|
}
|
|
8112
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
8113
|
-
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 }); }
|
|
8114
8662
|
}
|
|
8115
|
-
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: [{
|
|
8116
8664
|
type: Component,
|
|
8117
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"] }]
|
|
8118
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 }] }] } });
|
|
@@ -8179,10 +8727,10 @@ class IntroSrcComponent {
|
|
|
8179
8727
|
sourceElement.addEventListener('error', () => this.#store.dispatch(resetIntroSrc()));
|
|
8180
8728
|
videoContainer.appendChild(videoElement);
|
|
8181
8729
|
}
|
|
8182
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
8183
|
-
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 }); }
|
|
8184
8732
|
}
|
|
8185
|
-
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: [{
|
|
8186
8734
|
type: Component,
|
|
8187
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"] }]
|
|
8188
8736
|
}], ctorParameters: () => [], propDecorators: { videoElement: [{ type: i0.ViewChild, args: ['videoPlayerCover', { isSignal: true }] }] } });
|
|
@@ -8413,10 +8961,10 @@ class UnrealSceneComponent {
|
|
|
8413
8961
|
},
|
|
8414
8962
|
});
|
|
8415
8963
|
}
|
|
8416
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.
|
|
8417
|
-
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 }); }
|
|
8418
8966
|
}
|
|
8419
|
-
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: [{
|
|
8420
8968
|
type: Component,
|
|
8421
8969
|
args: [{ selector: 'app-unreal-scene', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
8422
8970
|
AfkTimeoutModalComponent,
|
|
@@ -8486,5 +9034,5 @@ function provideUnrealModule() {
|
|
|
8486
9034
|
* Generated bundle index. Do not edit.
|
|
8487
9035
|
*/
|
|
8488
9036
|
|
|
8489
|
-
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,
|
|
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 };
|
|
8490
9038
|
//# sourceMappingURL=3dsource-angular-unreal-module.mjs.map
|