@thestatic-tv/dcl-sdk 2.5.10 → 2.5.11
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/dist/index.d.mts +49 -2
- package/dist/index.d.ts +49 -2
- package/dist/index.js +410 -252
- package/dist/index.mjs +379 -223
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -625,6 +625,17 @@ var UI_DIMENSIONS = {
|
|
|
625
625
|
buttonHeightSmall: 30,
|
|
626
626
|
inputHeight: 36
|
|
627
627
|
},
|
|
628
|
+
// Notification banner - next to DCL native chat panel
|
|
629
|
+
notification: {
|
|
630
|
+
width: 340,
|
|
631
|
+
height: 44,
|
|
632
|
+
bottom: 55,
|
|
633
|
+
// Above the chat input area
|
|
634
|
+
left: 400,
|
|
635
|
+
// Right of DCL native chat (chat is ~380px wide)
|
|
636
|
+
borderWidth: 2,
|
|
637
|
+
fontSize: 14
|
|
638
|
+
},
|
|
628
639
|
// Shared
|
|
629
640
|
closeButton: {
|
|
630
641
|
size: 40,
|
|
@@ -2252,12 +2263,131 @@ var ChatUIModule = class {
|
|
|
2252
2263
|
};
|
|
2253
2264
|
|
|
2254
2265
|
// src/ui/admin-panel-ui.tsx
|
|
2255
|
-
import
|
|
2266
|
+
import ReactEcs5, { UiEntity as UiEntity5, Button as Button3, Label as Label5, Input as Input4 } from "@dcl/sdk/react-ecs";
|
|
2256
2267
|
import { Color4 as Color45, Vector3 } from "@dcl/sdk/math";
|
|
2257
2268
|
import { getPlayer as getPlayer2 } from "@dcl/sdk/players";
|
|
2258
2269
|
import { movePlayerTo, openExternalUrl as openExternalUrl3 } from "~system/RestrictedActions";
|
|
2270
|
+
|
|
2271
|
+
// src/ui/ui-renderer.tsx
|
|
2272
|
+
import ReactEcs4, { ReactEcsRenderer, UiEntity as UiEntity4, Label as Label4 } from "@dcl/sdk/react-ecs";
|
|
2273
|
+
import { engine as engine2 } from "@dcl/sdk/ecs";
|
|
2274
|
+
var notificationText = "";
|
|
2275
|
+
var notificationVisible = false;
|
|
2276
|
+
var notificationEndTime = 0;
|
|
2277
|
+
var notificationInitialized = false;
|
|
2278
|
+
var C = THEME.colors;
|
|
2279
|
+
var N = UI_DIMENSIONS.notification;
|
|
2280
|
+
function showNotification(message, durationMs = 5e3) {
|
|
2281
|
+
notificationText = message;
|
|
2282
|
+
notificationVisible = true;
|
|
2283
|
+
notificationEndTime = Date.now() + durationMs;
|
|
2284
|
+
}
|
|
2285
|
+
function hideNotification() {
|
|
2286
|
+
notificationVisible = false;
|
|
2287
|
+
}
|
|
2288
|
+
function initNotificationSystem() {
|
|
2289
|
+
if (notificationInitialized) return;
|
|
2290
|
+
notificationInitialized = true;
|
|
2291
|
+
engine2.addSystem(() => {
|
|
2292
|
+
if (notificationVisible && Date.now() > notificationEndTime) {
|
|
2293
|
+
notificationVisible = false;
|
|
2294
|
+
}
|
|
2295
|
+
});
|
|
2296
|
+
}
|
|
2297
|
+
function NotificationBanner() {
|
|
2298
|
+
initNotificationSystem();
|
|
2299
|
+
if (!notificationVisible) return null;
|
|
2300
|
+
return /* @__PURE__ */ ReactEcs4.createElement(
|
|
2301
|
+
UiEntity4,
|
|
2302
|
+
{
|
|
2303
|
+
uiTransform: {
|
|
2304
|
+
positionType: "absolute",
|
|
2305
|
+
position: { bottom: N.bottom, left: N.left },
|
|
2306
|
+
width: N.width,
|
|
2307
|
+
height: N.height,
|
|
2308
|
+
flexDirection: "row",
|
|
2309
|
+
alignItems: "center"
|
|
2310
|
+
},
|
|
2311
|
+
uiBackground: { color: C.panel }
|
|
2312
|
+
},
|
|
2313
|
+
/* @__PURE__ */ ReactEcs4.createElement(
|
|
2314
|
+
UiEntity4,
|
|
2315
|
+
{
|
|
2316
|
+
uiTransform: {
|
|
2317
|
+
width: N.borderWidth,
|
|
2318
|
+
height: "100%"
|
|
2319
|
+
},
|
|
2320
|
+
uiBackground: { color: C.cyan }
|
|
2321
|
+
}
|
|
2322
|
+
),
|
|
2323
|
+
/* @__PURE__ */ ReactEcs4.createElement(
|
|
2324
|
+
UiEntity4,
|
|
2325
|
+
{
|
|
2326
|
+
uiTransform: {
|
|
2327
|
+
flexGrow: 1,
|
|
2328
|
+
height: "100%",
|
|
2329
|
+
padding: { left: 12, right: 12 },
|
|
2330
|
+
justifyContent: "center",
|
|
2331
|
+
alignItems: "flex-start"
|
|
2332
|
+
}
|
|
2333
|
+
},
|
|
2334
|
+
/* @__PURE__ */ ReactEcs4.createElement(
|
|
2335
|
+
Label4,
|
|
2336
|
+
{
|
|
2337
|
+
value: notificationText,
|
|
2338
|
+
fontSize: N.fontSize,
|
|
2339
|
+
color: C.white,
|
|
2340
|
+
textAlign: "middle-left"
|
|
2341
|
+
}
|
|
2342
|
+
)
|
|
2343
|
+
),
|
|
2344
|
+
/* @__PURE__ */ ReactEcs4.createElement(
|
|
2345
|
+
UiEntity4,
|
|
2346
|
+
{
|
|
2347
|
+
uiTransform: {
|
|
2348
|
+
width: 6,
|
|
2349
|
+
height: 6,
|
|
2350
|
+
margin: { right: 12 }
|
|
2351
|
+
},
|
|
2352
|
+
uiBackground: { color: C.cyan }
|
|
2353
|
+
}
|
|
2354
|
+
)
|
|
2355
|
+
);
|
|
2356
|
+
}
|
|
2357
|
+
function createStaticUI(client) {
|
|
2358
|
+
initNotificationSystem();
|
|
2359
|
+
return function StaticUI() {
|
|
2360
|
+
const currentScale = client.uiScale;
|
|
2361
|
+
const guideComponent = client.guideUI?.getComponent() ?? null;
|
|
2362
|
+
const chatComponent = client.chatUI?.getComponent() ?? null;
|
|
2363
|
+
const adminComponent = client.adminPanel?.getComponent() ?? null;
|
|
2364
|
+
return /* @__PURE__ */ ReactEcs4.createElement(
|
|
2365
|
+
UiEntity4,
|
|
2366
|
+
{
|
|
2367
|
+
key: `static-ui-root-${currentScale}`,
|
|
2368
|
+
uiTransform: {
|
|
2369
|
+
width: "100%",
|
|
2370
|
+
height: "100%",
|
|
2371
|
+
positionType: "absolute",
|
|
2372
|
+
flexDirection: "column",
|
|
2373
|
+
alignItems: "center"
|
|
2374
|
+
}
|
|
2375
|
+
},
|
|
2376
|
+
/* @__PURE__ */ ReactEcs4.createElement(NotificationBanner, null),
|
|
2377
|
+
guideComponent,
|
|
2378
|
+
chatComponent,
|
|
2379
|
+
adminComponent
|
|
2380
|
+
);
|
|
2381
|
+
};
|
|
2382
|
+
}
|
|
2383
|
+
function setupStaticUI(client) {
|
|
2384
|
+
const StaticUI = createStaticUI(client);
|
|
2385
|
+
ReactEcsRenderer.setUiRenderer(StaticUI);
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
// src/ui/admin-panel-ui.tsx
|
|
2259
2389
|
var BAN_KICK_POSITION = Vector3.create(16, -50, 16);
|
|
2260
|
-
var
|
|
2390
|
+
var C2 = {
|
|
2261
2391
|
bg: Color45.create(0.08, 0.08, 0.12, 0.98),
|
|
2262
2392
|
header: Color45.create(0.9, 0.15, 0.15, 1),
|
|
2263
2393
|
tabActive: Color45.create(0, 0.7, 0.7, 1),
|
|
@@ -2298,6 +2428,8 @@ var AdminPanelUIModule = class {
|
|
|
2298
2428
|
this.streamControlling = false;
|
|
2299
2429
|
this.streamControlStatus = "";
|
|
2300
2430
|
this.pollIntervalId = null;
|
|
2431
|
+
this.commandPollIntervalId = null;
|
|
2432
|
+
this.lastCommandTimestamp = 0;
|
|
2301
2433
|
this.trialClaiming = false;
|
|
2302
2434
|
this.trialClaimError = "";
|
|
2303
2435
|
// Mod tab state
|
|
@@ -2309,22 +2441,22 @@ var AdminPanelUIModule = class {
|
|
|
2309
2441
|
this.modStatus = "";
|
|
2310
2442
|
this.modsFetched = false;
|
|
2311
2443
|
// --- UI Components ---
|
|
2312
|
-
this.SectionHead = ({ label, color }) => /* @__PURE__ */
|
|
2313
|
-
|
|
2444
|
+
this.SectionHead = ({ label, color }) => /* @__PURE__ */ ReactEcs5.createElement(
|
|
2445
|
+
UiEntity5,
|
|
2314
2446
|
{
|
|
2315
2447
|
uiTransform: { width: "100%", height: this.s(UI_DIMENSIONS.admin.sectionHeadHeight), margin: { bottom: 8 }, padding: { left: 10 }, alignItems: "center" },
|
|
2316
2448
|
uiBackground: { color: Color45.create(color.r * 0.3, color.g * 0.3, color.b * 0.3, 0.5) }
|
|
2317
2449
|
},
|
|
2318
|
-
/* @__PURE__ */
|
|
2450
|
+
/* @__PURE__ */ ReactEcs5.createElement(Label5, { value: label, fontSize: this.theme.sectionHead, color })
|
|
2319
2451
|
);
|
|
2320
|
-
this.TabBtn = ({ label, tab }) => /* @__PURE__ */
|
|
2452
|
+
this.TabBtn = ({ label, tab }) => /* @__PURE__ */ ReactEcs5.createElement(
|
|
2321
2453
|
Button3,
|
|
2322
2454
|
{
|
|
2323
2455
|
uiTransform: { flexGrow: 1, height: this.s(UI_DIMENSIONS.admin.tabHeight), justifyContent: "center", alignItems: "center" },
|
|
2324
|
-
uiBackground: { color: this.activeTab === tab ?
|
|
2456
|
+
uiBackground: { color: this.activeTab === tab ? C2.tabActive : C2.tabInactive },
|
|
2325
2457
|
value: label,
|
|
2326
2458
|
fontSize: this.theme.tabButton,
|
|
2327
|
-
color: this.activeTab === tab ? Color45.Black() :
|
|
2459
|
+
color: this.activeTab === tab ? Color45.Black() : C2.text,
|
|
2328
2460
|
textAlign: "middle-center",
|
|
2329
2461
|
onMouseDown: () => this.setActiveTab(tab)
|
|
2330
2462
|
}
|
|
@@ -2334,365 +2466,368 @@ var AdminPanelUIModule = class {
|
|
|
2334
2466
|
this.fetchStreamData();
|
|
2335
2467
|
}
|
|
2336
2468
|
const t = this.theme;
|
|
2337
|
-
return /* @__PURE__ */
|
|
2469
|
+
return /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "column", width: "100%", padding: 10 } }, !this.streamData?.hasChannel && /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "column", margin: { bottom: 14 } } }, /* @__PURE__ */ ReactEcs5.createElement(this.SectionHead, { label: "LIVE STREAM", color: C2.btn }), /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: "No streaming channel linked", fontSize: t.labelSmall, color: C2.textDim, uiTransform: { margin: { bottom: 8 } } }), this.isOwner && /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "column" } }, this.streamData?.trialAvailable && /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "column", margin: { bottom: 10 } } }, /* @__PURE__ */ ReactEcs5.createElement(
|
|
2338
2470
|
Button3,
|
|
2339
2471
|
{
|
|
2340
2472
|
uiTransform: { width: this.s(200), height: this.s(UI_DIMENSIONS.admin.buttonHeight), margin: { bottom: 6 } },
|
|
2341
|
-
uiBackground: { color: this.trialClaiming ?
|
|
2473
|
+
uiBackground: { color: this.trialClaiming ? C2.btn : C2.green },
|
|
2342
2474
|
value: this.trialClaiming ? "Claiming..." : "Start Free 4-Hour Trial",
|
|
2343
2475
|
fontSize: t.button,
|
|
2344
|
-
color:
|
|
2476
|
+
color: C2.text,
|
|
2345
2477
|
onMouseDown: () => this.claimTrial()
|
|
2346
2478
|
}
|
|
2347
|
-
), this.trialClaimError && /* @__PURE__ */
|
|
2479
|
+
), this.trialClaimError && /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: this.trialClaimError, fontSize: t.status, color: C2.red }), /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: "One-time trial \u2022 4 hours of streaming", fontSize: t.labelSmall, color: C2.textDim, uiTransform: { margin: { top: 4 } } })), !this.streamData?.trialAvailable && /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "column" } }, /* @__PURE__ */ ReactEcs5.createElement(
|
|
2348
2480
|
Button3,
|
|
2349
2481
|
{
|
|
2350
2482
|
uiTransform: { width: this.s(170), height: this.s(UI_DIMENSIONS.admin.buttonHeight), margin: { bottom: 6 } },
|
|
2351
|
-
uiBackground: { color: this.channelCreating ?
|
|
2483
|
+
uiBackground: { color: this.channelCreating ? C2.btn : C2.cyan },
|
|
2352
2484
|
value: this.channelCreating ? "Creating..." : "+ Create Channel",
|
|
2353
2485
|
fontSize: t.button,
|
|
2354
|
-
color:
|
|
2486
|
+
color: C2.text,
|
|
2355
2487
|
onMouseDown: () => this.createChannel()
|
|
2356
2488
|
}
|
|
2357
|
-
), this.channelCreateError && /* @__PURE__ */
|
|
2358
|
-
|
|
2489
|
+
), this.channelCreateError && /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: this.channelCreateError, fontSize: t.status, color: C2.red }), /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: "Relay tier \u2022 $25/mo \u2022 8 hours streaming", fontSize: t.labelSmall, color: C2.textDim, uiTransform: { margin: { top: 4 } } })))), this.streamData?.hasChannel && this.isOwner && /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "column", margin: { bottom: 14 } } }, /* @__PURE__ */ ReactEcs5.createElement(this.SectionHead, { label: this.streamData.isLive ? "LIVE STREAM" : "STREAM SETTINGS", color: this.streamData.isLive ? C2.red : C2.yellow }), /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "row", alignItems: "center", margin: { bottom: 8 } } }, /* @__PURE__ */ ReactEcs5.createElement(
|
|
2490
|
+
Label5,
|
|
2359
2491
|
{
|
|
2360
2492
|
value: this.streamData.isLive ? `LIVE \u2022 ${this.streamData.currentViewers || 0} viewers` : "OFFLINE",
|
|
2361
2493
|
fontSize: t.label,
|
|
2362
|
-
color: this.streamData.isLive ?
|
|
2494
|
+
color: this.streamData.isLive ? C2.red : C2.textDim
|
|
2363
2495
|
}
|
|
2364
|
-
), /* @__PURE__ */
|
|
2365
|
-
|
|
2496
|
+
), /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: ` \u2022 ${this.streamData.tier?.toUpperCase() || "RELAY"}`, fontSize: t.labelSmall, color: C2.cyan }), /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: ` \u2022 ${this.streamData.sparksBalance || 0} Sparks`, fontSize: t.labelSmall, color: C2.textDim })), /* @__PURE__ */ ReactEcs5.createElement(
|
|
2497
|
+
Label5,
|
|
2366
2498
|
{
|
|
2367
2499
|
value: `Channel: ${this.streamData.channelName || this.streamData.channelId}`,
|
|
2368
2500
|
fontSize: t.labelSmall,
|
|
2369
|
-
color:
|
|
2501
|
+
color: C2.textDim,
|
|
2370
2502
|
uiTransform: { margin: { bottom: 10 } }
|
|
2371
2503
|
}
|
|
2372
|
-
), /* @__PURE__ */
|
|
2373
|
-
|
|
2504
|
+
), /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "column", margin: { bottom: 6 } } }, /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: "RTMP Server:", fontSize: t.labelSmall, color: C2.textDim }), /* @__PURE__ */ ReactEcs5.createElement(
|
|
2505
|
+
Label5,
|
|
2374
2506
|
{
|
|
2375
2507
|
value: this.streamData.rtmpUrl || "Loading...",
|
|
2376
2508
|
fontSize: t.label,
|
|
2377
|
-
color: this.streamData.rtmpUrl ?
|
|
2509
|
+
color: this.streamData.rtmpUrl ? C2.text : C2.textDim,
|
|
2378
2510
|
uiTransform: { margin: { left: 6 } }
|
|
2379
2511
|
}
|
|
2380
|
-
)), /* @__PURE__ */
|
|
2381
|
-
|
|
2512
|
+
)), /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "column", margin: { bottom: 6 } } }, /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: "Stream Key:", fontSize: t.labelSmall, color: C2.textDim }), /* @__PURE__ */ ReactEcs5.createElement(
|
|
2513
|
+
Label5,
|
|
2382
2514
|
{
|
|
2383
2515
|
value: this.streamData.streamKey || "Loading...",
|
|
2384
2516
|
fontSize: t.label,
|
|
2385
|
-
color: this.streamData.streamKey ?
|
|
2517
|
+
color: this.streamData.streamKey ? C2.cyan : C2.textDim,
|
|
2386
2518
|
uiTransform: { margin: { left: 6 } }
|
|
2387
2519
|
}
|
|
2388
|
-
)), /* @__PURE__ */
|
|
2389
|
-
|
|
2520
|
+
)), /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "column", margin: { bottom: 10 } } }, /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: "HLS Playback:", fontSize: t.labelSmall, color: C2.textDim }), /* @__PURE__ */ ReactEcs5.createElement(
|
|
2521
|
+
Label5,
|
|
2390
2522
|
{
|
|
2391
2523
|
value: this.streamData.hlsUrl || "Not available",
|
|
2392
2524
|
fontSize: t.label,
|
|
2393
|
-
color: this.streamData.hlsUrl ?
|
|
2525
|
+
color: this.streamData.hlsUrl ? C2.green : C2.textDim,
|
|
2394
2526
|
uiTransform: { margin: { left: 6 } }
|
|
2395
2527
|
}
|
|
2396
|
-
)), /* @__PURE__ */
|
|
2528
|
+
)), /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "row", flexWrap: "wrap", margin: { bottom: 6 } } }, !this.streamData.isLive && /* @__PURE__ */ ReactEcs5.createElement(
|
|
2397
2529
|
Button3,
|
|
2398
2530
|
{
|
|
2399
2531
|
uiTransform: { width: this.s(110), height: this.s(UI_DIMENSIONS.admin.buttonHeightSmall), margin: 4 },
|
|
2400
|
-
uiBackground: { color: this.streamControlling ?
|
|
2532
|
+
uiBackground: { color: this.streamControlling ? C2.btn : C2.green },
|
|
2401
2533
|
value: this.streamControlling ? "Starting..." : "Start Stream",
|
|
2402
2534
|
fontSize: t.buttonSmall,
|
|
2403
|
-
color:
|
|
2535
|
+
color: C2.text,
|
|
2404
2536
|
onMouseDown: () => this.startStream()
|
|
2405
2537
|
}
|
|
2406
|
-
), this.streamData.isLive && /* @__PURE__ */
|
|
2538
|
+
), this.streamData.isLive && /* @__PURE__ */ ReactEcs5.createElement(
|
|
2407
2539
|
Button3,
|
|
2408
2540
|
{
|
|
2409
2541
|
uiTransform: { width: this.s(110), height: this.s(UI_DIMENSIONS.admin.buttonHeightSmall), margin: 4 },
|
|
2410
|
-
uiBackground: { color: this.streamControlling ?
|
|
2542
|
+
uiBackground: { color: this.streamControlling ? C2.btn : C2.red },
|
|
2411
2543
|
value: this.streamControlling ? "Stopping..." : "Stop Stream",
|
|
2412
2544
|
fontSize: t.buttonSmall,
|
|
2413
|
-
color:
|
|
2545
|
+
color: C2.text,
|
|
2414
2546
|
onMouseDown: () => this.stopStream()
|
|
2415
2547
|
}
|
|
2416
|
-
), this.streamData.isLive && this.streamData.hlsUrl && /* @__PURE__ */
|
|
2548
|
+
), this.streamData.isLive && this.streamData.hlsUrl && /* @__PURE__ */ ReactEcs5.createElement(
|
|
2417
2549
|
Button3,
|
|
2418
2550
|
{
|
|
2419
2551
|
uiTransform: { width: this.s(100), height: this.s(UI_DIMENSIONS.admin.buttonHeightSmall), margin: 4 },
|
|
2420
|
-
uiBackground: { color:
|
|
2552
|
+
uiBackground: { color: C2.cyan },
|
|
2421
2553
|
value: "Play on Screen",
|
|
2422
2554
|
fontSize: t.buttonSmall,
|
|
2423
|
-
color:
|
|
2555
|
+
color: C2.text,
|
|
2424
2556
|
onMouseDown: () => this.config.onVideoPlay?.(this.streamData.hlsUrl)
|
|
2425
2557
|
}
|
|
2426
|
-
)), /* @__PURE__ */
|
|
2558
|
+
)), /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "row", flexWrap: "wrap", margin: { bottom: 6 } } }, /* @__PURE__ */ ReactEcs5.createElement(
|
|
2427
2559
|
Button3,
|
|
2428
2560
|
{
|
|
2429
2561
|
uiTransform: { width: this.s(80), height: this.s(UI_DIMENSIONS.admin.buttonHeightSmall), margin: 4 },
|
|
2430
|
-
uiBackground: { color:
|
|
2562
|
+
uiBackground: { color: C2.btn },
|
|
2431
2563
|
value: "Refresh",
|
|
2432
2564
|
fontSize: t.buttonSmall,
|
|
2433
|
-
color:
|
|
2565
|
+
color: C2.text,
|
|
2434
2566
|
onMouseDown: () => this.refreshStreamStatus()
|
|
2435
2567
|
}
|
|
2436
|
-
), /* @__PURE__ */
|
|
2568
|
+
), /* @__PURE__ */ ReactEcs5.createElement(
|
|
2437
2569
|
Button3,
|
|
2438
2570
|
{
|
|
2439
2571
|
uiTransform: { width: this.s(95), height: this.s(UI_DIMENSIONS.admin.buttonHeightSmall), margin: 4 },
|
|
2440
|
-
uiBackground: { color: this.keyRotating ?
|
|
2572
|
+
uiBackground: { color: this.keyRotating ? C2.btn : C2.yellow },
|
|
2441
2573
|
value: this.keyRotating ? "..." : "Rotate Key",
|
|
2442
2574
|
fontSize: t.buttonSmall,
|
|
2443
|
-
color:
|
|
2575
|
+
color: C2.text,
|
|
2444
2576
|
onMouseDown: () => this.rotateStreamKey()
|
|
2445
2577
|
}
|
|
2446
|
-
), !this.streamData.isLive && /* @__PURE__ */
|
|
2578
|
+
), !this.streamData.isLive && /* @__PURE__ */ ReactEcs5.createElement(
|
|
2447
2579
|
Button3,
|
|
2448
2580
|
{
|
|
2449
2581
|
uiTransform: { width: this.s(70), height: this.s(UI_DIMENSIONS.admin.buttonHeightSmall), margin: 4 },
|
|
2450
|
-
uiBackground: { color: this.channelDeleting ?
|
|
2582
|
+
uiBackground: { color: this.channelDeleting ? C2.btn : C2.red },
|
|
2451
2583
|
value: this.channelDeleting ? "..." : "Delete",
|
|
2452
2584
|
fontSize: t.buttonSmall,
|
|
2453
|
-
color:
|
|
2585
|
+
color: C2.text,
|
|
2454
2586
|
onMouseDown: () => this.deleteChannel()
|
|
2455
2587
|
}
|
|
2456
|
-
)), this.streamControlStatus === "started" && /* @__PURE__ */
|
|
2588
|
+
)), this.streamControlStatus === "started" && /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: "Stream started - begin broadcasting in OBS", fontSize: t.status, color: C2.green }), this.streamControlStatus === "stopped" && /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: "Stream stopped", fontSize: t.status, color: C2.textDim }), this.keyRotateStatus === "success" && /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: "Key rotated! Update OBS", fontSize: t.status, color: C2.green }), this.keyRotateStatus === "error" && /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: "Failed to rotate key", fontSize: t.status, color: C2.red }), this.channelDeleteError && /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: this.channelDeleteError, fontSize: t.status, color: C2.red }), this.streamControlStatus === "error" && /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: "Stream control failed", fontSize: t.status, color: C2.red })), /* @__PURE__ */ ReactEcs5.createElement(this.SectionHead, { label: "PLAY NOW", color: C2.orange }), /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "row", alignItems: "center", margin: { bottom: 14 } } }, /* @__PURE__ */ ReactEcs5.createElement(
|
|
2457
2589
|
Input4,
|
|
2458
2590
|
{
|
|
2459
2591
|
uiTransform: { width: this.s(230), height: this.s(UI_DIMENSIONS.admin.inputHeight) },
|
|
2460
2592
|
uiBackground: { color: Color45.create(0.15, 0.15, 0.2, 1) },
|
|
2461
2593
|
placeholder: "Video URL...",
|
|
2462
|
-
placeholderColor:
|
|
2463
|
-
color:
|
|
2594
|
+
placeholderColor: C2.textDim,
|
|
2595
|
+
color: C2.text,
|
|
2464
2596
|
fontSize: t.input,
|
|
2465
2597
|
value: this.customVideoUrl,
|
|
2466
2598
|
onChange: (val) => {
|
|
2467
2599
|
this.customVideoUrl = val;
|
|
2468
2600
|
}
|
|
2469
2601
|
}
|
|
2470
|
-
), /* @__PURE__ */
|
|
2602
|
+
), /* @__PURE__ */ ReactEcs5.createElement(
|
|
2471
2603
|
Button3,
|
|
2472
2604
|
{
|
|
2473
2605
|
uiTransform: { width: this.s(75), height: this.s(UI_DIMENSIONS.admin.inputHeight), margin: { left: 8 } },
|
|
2474
|
-
uiBackground: { color:
|
|
2606
|
+
uiBackground: { color: C2.green },
|
|
2475
2607
|
value: "Play",
|
|
2476
2608
|
fontSize: t.button,
|
|
2477
|
-
color:
|
|
2609
|
+
color: C2.text,
|
|
2478
2610
|
onMouseDown: () => {
|
|
2479
2611
|
if (this.customVideoUrl) this.config.onVideoPlay?.(this.customVideoUrl);
|
|
2480
2612
|
}
|
|
2481
2613
|
}
|
|
2482
|
-
), /* @__PURE__ */
|
|
2614
|
+
), /* @__PURE__ */ ReactEcs5.createElement(
|
|
2483
2615
|
Button3,
|
|
2484
2616
|
{
|
|
2485
2617
|
uiTransform: { width: this.s(65), height: this.s(UI_DIMENSIONS.admin.inputHeight), margin: { left: 6 } },
|
|
2486
|
-
uiBackground: { color:
|
|
2618
|
+
uiBackground: { color: C2.btn },
|
|
2487
2619
|
value: "Clear",
|
|
2488
2620
|
fontSize: t.button,
|
|
2489
|
-
color:
|
|
2621
|
+
color: C2.text,
|
|
2490
2622
|
onMouseDown: () => {
|
|
2491
2623
|
this.customVideoUrl = "";
|
|
2492
2624
|
}
|
|
2493
2625
|
}
|
|
2494
|
-
)), /* @__PURE__ */
|
|
2626
|
+
)), /* @__PURE__ */ ReactEcs5.createElement(this.SectionHead, { label: "PLAYBACK", color: C2.green }), /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "row", flexWrap: "wrap", margin: { bottom: 14 } } }, /* @__PURE__ */ ReactEcs5.createElement(
|
|
2495
2627
|
Button3,
|
|
2496
2628
|
{
|
|
2497
2629
|
uiTransform: { width: this.s(75), height: this.s(UI_DIMENSIONS.admin.buttonHeightSmall), margin: 4 },
|
|
2498
|
-
uiBackground: { color:
|
|
2630
|
+
uiBackground: { color: C2.green },
|
|
2499
2631
|
value: "Play",
|
|
2500
2632
|
fontSize: t.button,
|
|
2501
|
-
color:
|
|
2633
|
+
color: C2.text,
|
|
2502
2634
|
onMouseDown: () => this.config.onCommand?.("videoPlay", { playing: true })
|
|
2503
2635
|
}
|
|
2504
|
-
), /* @__PURE__ */
|
|
2636
|
+
), /* @__PURE__ */ ReactEcs5.createElement(
|
|
2505
2637
|
Button3,
|
|
2506
2638
|
{
|
|
2507
2639
|
uiTransform: { width: this.s(75), height: this.s(UI_DIMENSIONS.admin.buttonHeightSmall), margin: 4 },
|
|
2508
|
-
uiBackground: { color:
|
|
2640
|
+
uiBackground: { color: C2.red },
|
|
2509
2641
|
value: "Stop",
|
|
2510
2642
|
fontSize: t.button,
|
|
2511
|
-
color:
|
|
2643
|
+
color: C2.text,
|
|
2512
2644
|
onMouseDown: () => this.config.onVideoStop?.()
|
|
2513
2645
|
}
|
|
2514
|
-
), /* @__PURE__ */
|
|
2646
|
+
), /* @__PURE__ */ ReactEcs5.createElement(
|
|
2515
2647
|
Button3,
|
|
2516
2648
|
{
|
|
2517
2649
|
uiTransform: { width: this.s(100), height: this.s(UI_DIMENSIONS.admin.buttonHeightSmall), margin: 4 },
|
|
2518
|
-
uiBackground: { color:
|
|
2650
|
+
uiBackground: { color: C2.btn },
|
|
2519
2651
|
value: "Reset Default",
|
|
2520
2652
|
fontSize: t.buttonSmall,
|
|
2521
|
-
color:
|
|
2653
|
+
color: C2.text,
|
|
2522
2654
|
onMouseDown: () => this.config.onCommand?.("videoClear", {})
|
|
2523
2655
|
}
|
|
2524
|
-
)), /* @__PURE__ */
|
|
2656
|
+
)), /* @__PURE__ */ ReactEcs5.createElement(this.SectionHead, { label: "VIDEO SLOTS", color: C2.cyan }), /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "row", flexWrap: "wrap", margin: { bottom: 10 } } }, /* @__PURE__ */ ReactEcs5.createElement(Button3, { uiTransform: { width: this.s(70), height: this.s(UI_DIMENSIONS.admin.buttonHeightSmall), margin: 4 }, uiBackground: { color: C2.cyan }, value: "Play 1", fontSize: t.button, color: C2.text, onMouseDown: () => this.playSlot("slot1") }), /* @__PURE__ */ ReactEcs5.createElement(Button3, { uiTransform: { width: this.s(70), height: this.s(UI_DIMENSIONS.admin.buttonHeightSmall), margin: 4 }, uiBackground: { color: C2.cyan }, value: "Play 2", fontSize: t.button, color: C2.text, onMouseDown: () => this.playSlot("slot2") }), /* @__PURE__ */ ReactEcs5.createElement(Button3, { uiTransform: { width: this.s(70), height: this.s(UI_DIMENSIONS.admin.buttonHeightSmall), margin: 4 }, uiBackground: { color: C2.cyan }, value: "Play 3", fontSize: t.button, color: C2.text, onMouseDown: () => this.playSlot("slot3") }), /* @__PURE__ */ ReactEcs5.createElement(Button3, { uiTransform: { width: this.s(70), height: this.s(UI_DIMENSIONS.admin.buttonHeightSmall), margin: 4 }, uiBackground: { color: C2.cyan }, value: "Play 4", fontSize: t.button, color: C2.text, onMouseDown: () => this.playSlot("slot4") }), /* @__PURE__ */ ReactEcs5.createElement(Button3, { uiTransform: { width: this.s(70), height: this.s(UI_DIMENSIONS.admin.buttonHeightSmall), margin: 4 }, uiBackground: { color: C2.cyan }, value: "Play 5", fontSize: t.button, color: C2.text, onMouseDown: () => this.playSlot("slot5") })), /* @__PURE__ */ ReactEcs5.createElement(
|
|
2525
2657
|
Button3,
|
|
2526
2658
|
{
|
|
2527
2659
|
uiTransform: { height: this.s(24) },
|
|
2528
2660
|
uiBackground: { color: Color45.create(0, 0, 0, 0) },
|
|
2529
2661
|
value: "Edit slots at thestatic.tv",
|
|
2530
2662
|
fontSize: t.labelSmall,
|
|
2531
|
-
color:
|
|
2663
|
+
color: C2.cyan,
|
|
2532
2664
|
onMouseDown: () => openExternalUrl3({ url: this.config.footerLink || `https://thestatic.tv/scene/${this.config.sceneId}` })
|
|
2533
2665
|
}
|
|
2534
2666
|
));
|
|
2535
2667
|
};
|
|
2536
2668
|
this.ModTab = () => {
|
|
2537
2669
|
const t = this.theme;
|
|
2538
|
-
return /* @__PURE__ */
|
|
2670
|
+
return /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "column", width: "100%", padding: 10 } }, this.modStatus === "loading" && /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: "Loading...", fontSize: t.status, color: C2.yellow }), this.modStatus === "saved" && /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: "Saved!", fontSize: t.status, color: C2.green }), this.modStatus === "error" && /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: "Error - check input", fontSize: t.status, color: C2.red }), /* @__PURE__ */ ReactEcs5.createElement(this.SectionHead, { label: "BROADCAST", color: C2.orange }), /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "row", alignItems: "center", margin: { bottom: 14 } } }, /* @__PURE__ */ ReactEcs5.createElement(
|
|
2539
2671
|
Input4,
|
|
2540
2672
|
{
|
|
2541
2673
|
uiTransform: { width: this.s(230), height: this.s(UI_DIMENSIONS.admin.inputHeight) },
|
|
2542
2674
|
uiBackground: { color: Color45.create(0.15, 0.15, 0.2, 1) },
|
|
2543
2675
|
placeholder: "Message to all players...",
|
|
2544
|
-
placeholderColor:
|
|
2545
|
-
color:
|
|
2676
|
+
placeholderColor: C2.textDim,
|
|
2677
|
+
color: C2.text,
|
|
2546
2678
|
fontSize: t.input,
|
|
2547
2679
|
value: this.broadcastText,
|
|
2548
2680
|
onChange: (val) => {
|
|
2549
2681
|
this.broadcastText = val;
|
|
2550
2682
|
}
|
|
2551
2683
|
}
|
|
2552
|
-
), /* @__PURE__ */
|
|
2684
|
+
), /* @__PURE__ */ ReactEcs5.createElement(
|
|
2553
2685
|
Button3,
|
|
2554
2686
|
{
|
|
2555
2687
|
uiTransform: { width: this.s(65), height: this.s(UI_DIMENSIONS.admin.inputHeight), margin: { left: 8 } },
|
|
2556
|
-
uiBackground: { color:
|
|
2688
|
+
uiBackground: { color: C2.orange },
|
|
2557
2689
|
value: "Send",
|
|
2558
2690
|
fontSize: t.button,
|
|
2559
|
-
color:
|
|
2691
|
+
color: C2.text,
|
|
2560
2692
|
onMouseDown: () => this.sendBroadcast()
|
|
2561
2693
|
}
|
|
2562
|
-
)), /* @__PURE__ */
|
|
2694
|
+
)), /* @__PURE__ */ ReactEcs5.createElement(this.SectionHead, { label: "CHAOS MODE", color: C2.red }), /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "row", flexWrap: "wrap", margin: { bottom: 14 } } }, /* @__PURE__ */ ReactEcs5.createElement(
|
|
2563
2695
|
Button3,
|
|
2564
2696
|
{
|
|
2565
2697
|
uiTransform: { width: this.s(130), height: this.s(UI_DIMENSIONS.admin.buttonHeight), margin: 4 },
|
|
2566
|
-
uiBackground: { color:
|
|
2698
|
+
uiBackground: { color: C2.red },
|
|
2567
2699
|
value: "KICK ALL",
|
|
2568
2700
|
fontSize: t.button,
|
|
2569
|
-
color:
|
|
2701
|
+
color: C2.text,
|
|
2570
2702
|
onMouseDown: () => {
|
|
2571
2703
|
this.log("KICK ALL clicked");
|
|
2572
2704
|
this.config.onCommand?.("kickAll", {});
|
|
2573
2705
|
}
|
|
2574
2706
|
}
|
|
2575
|
-
)), /* @__PURE__ */
|
|
2576
|
-
|
|
2707
|
+
)), /* @__PURE__ */ ReactEcs5.createElement(this.SectionHead, { label: "SCENE ADMINS", color: C2.purple }), /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "column", margin: { bottom: 6 } } }, this.sceneAdmins.length === 0 && this.modStatus !== "loading" && /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: "No scene admins", fontSize: t.labelSmall, color: C2.textDim }), this.sceneAdmins.map((wallet, i) => /* @__PURE__ */ ReactEcs5.createElement(
|
|
2708
|
+
UiEntity5,
|
|
2577
2709
|
{
|
|
2578
2710
|
key: `admin-${i}`,
|
|
2579
2711
|
uiTransform: { flexDirection: "row", alignItems: "center", margin: { bottom: 5 }, width: "100%" }
|
|
2580
2712
|
},
|
|
2581
|
-
/* @__PURE__ */
|
|
2582
|
-
|
|
2713
|
+
/* @__PURE__ */ ReactEcs5.createElement(
|
|
2714
|
+
Label5,
|
|
2583
2715
|
{
|
|
2584
2716
|
value: `${wallet.slice(0, 6)}...${wallet.slice(-4)}`,
|
|
2585
2717
|
fontSize: t.label,
|
|
2586
|
-
color:
|
|
2718
|
+
color: C2.text,
|
|
2587
2719
|
uiTransform: { width: this.s(130) }
|
|
2588
2720
|
}
|
|
2589
2721
|
),
|
|
2590
|
-
/* @__PURE__ */
|
|
2722
|
+
/* @__PURE__ */ ReactEcs5.createElement(
|
|
2591
2723
|
Button3,
|
|
2592
2724
|
{
|
|
2593
2725
|
uiTransform: { width: this.s(70), height: this.s(28), margin: { left: 8 } },
|
|
2594
|
-
uiBackground: { color:
|
|
2726
|
+
uiBackground: { color: C2.btn },
|
|
2595
2727
|
value: "Remove",
|
|
2596
2728
|
fontSize: t.buttonSmall,
|
|
2597
|
-
color:
|
|
2729
|
+
color: C2.text,
|
|
2598
2730
|
onMouseDown: () => this.removeSceneAdmin(wallet)
|
|
2599
2731
|
}
|
|
2600
2732
|
)
|
|
2601
|
-
))), /* @__PURE__ */
|
|
2733
|
+
))), /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "row", alignItems: "center", margin: { bottom: 14 } } }, /* @__PURE__ */ ReactEcs5.createElement(
|
|
2602
2734
|
Input4,
|
|
2603
2735
|
{
|
|
2604
2736
|
uiTransform: { width: this.s(230), height: this.s(UI_DIMENSIONS.admin.inputHeight) },
|
|
2605
2737
|
uiBackground: { color: Color45.create(0.15, 0.15, 0.2, 1) },
|
|
2606
2738
|
placeholder: "0x... add admin",
|
|
2607
|
-
placeholderColor:
|
|
2608
|
-
color:
|
|
2739
|
+
placeholderColor: C2.textDim,
|
|
2740
|
+
color: C2.text,
|
|
2609
2741
|
fontSize: t.input,
|
|
2610
2742
|
value: this.newAdminWallet,
|
|
2611
2743
|
onChange: (val) => {
|
|
2612
2744
|
this.newAdminWallet = val;
|
|
2613
2745
|
}
|
|
2614
2746
|
}
|
|
2615
|
-
), /* @__PURE__ */
|
|
2747
|
+
), /* @__PURE__ */ ReactEcs5.createElement(
|
|
2616
2748
|
Button3,
|
|
2617
2749
|
{
|
|
2618
2750
|
uiTransform: { width: this.s(60), height: this.s(UI_DIMENSIONS.admin.inputHeight), margin: { left: 8 } },
|
|
2619
|
-
uiBackground: { color:
|
|
2751
|
+
uiBackground: { color: C2.purple },
|
|
2620
2752
|
value: "Add",
|
|
2621
2753
|
fontSize: t.button,
|
|
2622
|
-
color:
|
|
2754
|
+
color: C2.text,
|
|
2623
2755
|
onMouseDown: () => {
|
|
2624
2756
|
if (this.newAdminWallet) this.addSceneAdmin(this.newAdminWallet);
|
|
2625
2757
|
}
|
|
2626
2758
|
}
|
|
2627
|
-
)), /* @__PURE__ */
|
|
2628
|
-
|
|
2759
|
+
)), /* @__PURE__ */ ReactEcs5.createElement(this.SectionHead, { label: "BANNED WALLETS", color: C2.red }), /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "column", margin: { bottom: 6 } } }, this.bannedWallets.length === 0 && this.modStatus !== "loading" && /* @__PURE__ */ ReactEcs5.createElement(Label5, { value: "No banned wallets", fontSize: t.labelSmall, color: C2.textDim }), this.bannedWallets.map((wallet, i) => /* @__PURE__ */ ReactEcs5.createElement(
|
|
2760
|
+
UiEntity5,
|
|
2629
2761
|
{
|
|
2630
2762
|
key: `ban-${i}`,
|
|
2631
2763
|
uiTransform: { flexDirection: "row", alignItems: "center", margin: { bottom: 5 }, width: "100%" }
|
|
2632
2764
|
},
|
|
2633
|
-
/* @__PURE__ */
|
|
2634
|
-
|
|
2765
|
+
/* @__PURE__ */ ReactEcs5.createElement(
|
|
2766
|
+
Label5,
|
|
2635
2767
|
{
|
|
2636
2768
|
value: `${wallet.slice(0, 6)}...${wallet.slice(-4)}`,
|
|
2637
2769
|
fontSize: t.label,
|
|
2638
|
-
color:
|
|
2770
|
+
color: C2.red,
|
|
2639
2771
|
uiTransform: { width: this.s(130) }
|
|
2640
2772
|
}
|
|
2641
2773
|
),
|
|
2642
|
-
/* @__PURE__ */
|
|
2774
|
+
/* @__PURE__ */ ReactEcs5.createElement(
|
|
2643
2775
|
Button3,
|
|
2644
2776
|
{
|
|
2645
2777
|
uiTransform: { width: this.s(70), height: this.s(28), margin: { left: 8 } },
|
|
2646
|
-
uiBackground: { color:
|
|
2778
|
+
uiBackground: { color: C2.green },
|
|
2647
2779
|
value: "Unban",
|
|
2648
2780
|
fontSize: t.buttonSmall,
|
|
2649
|
-
color:
|
|
2781
|
+
color: C2.text,
|
|
2650
2782
|
onMouseDown: () => this.unbanWallet(wallet)
|
|
2651
2783
|
}
|
|
2652
2784
|
)
|
|
2653
|
-
))), /* @__PURE__ */
|
|
2785
|
+
))), /* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { flexDirection: "row", alignItems: "center", margin: { bottom: 10 } } }, /* @__PURE__ */ ReactEcs5.createElement(
|
|
2654
2786
|
Input4,
|
|
2655
2787
|
{
|
|
2656
2788
|
uiTransform: { width: this.s(230), height: this.s(UI_DIMENSIONS.admin.inputHeight) },
|
|
2657
2789
|
uiBackground: { color: Color45.create(0.15, 0.15, 0.2, 1) },
|
|
2658
2790
|
placeholder: "0x... ban wallet",
|
|
2659
|
-
placeholderColor:
|
|
2660
|
-
color:
|
|
2791
|
+
placeholderColor: C2.textDim,
|
|
2792
|
+
color: C2.text,
|
|
2661
2793
|
fontSize: t.input,
|
|
2662
2794
|
value: this.newBanWallet,
|
|
2663
2795
|
onChange: (val) => {
|
|
2664
2796
|
this.newBanWallet = val;
|
|
2665
2797
|
}
|
|
2666
2798
|
}
|
|
2667
|
-
), /* @__PURE__ */
|
|
2799
|
+
), /* @__PURE__ */ ReactEcs5.createElement(
|
|
2668
2800
|
Button3,
|
|
2669
2801
|
{
|
|
2670
2802
|
uiTransform: { width: this.s(60), height: this.s(UI_DIMENSIONS.admin.inputHeight), margin: { left: 8 } },
|
|
2671
|
-
uiBackground: { color:
|
|
2803
|
+
uiBackground: { color: C2.red },
|
|
2672
2804
|
value: "Ban",
|
|
2673
2805
|
fontSize: t.button,
|
|
2674
|
-
color:
|
|
2806
|
+
color: C2.text,
|
|
2675
2807
|
onMouseDown: () => {
|
|
2676
2808
|
if (this.newBanWallet) this.banWallet(this.newBanWallet);
|
|
2677
2809
|
}
|
|
2678
2810
|
}
|
|
2679
|
-
)), /* @__PURE__ */
|
|
2811
|
+
)), /* @__PURE__ */ ReactEcs5.createElement(
|
|
2680
2812
|
Button3,
|
|
2681
2813
|
{
|
|
2682
2814
|
uiTransform: { height: this.s(24) },
|
|
2683
2815
|
uiBackground: { color: Color45.create(0, 0, 0, 0) },
|
|
2684
2816
|
value: "Manage at thestatic.tv",
|
|
2685
2817
|
fontSize: t.labelSmall,
|
|
2686
|
-
color:
|
|
2818
|
+
color: C2.cyan,
|
|
2687
2819
|
onMouseDown: () => openExternalUrl3({ url: this.config.footerLink || `https://thestatic.tv/scene/${this.config.sceneId}` })
|
|
2688
2820
|
}
|
|
2689
2821
|
));
|
|
2690
2822
|
};
|
|
2691
2823
|
/**
|
|
2692
2824
|
* Get the React-ECS component for the admin panel
|
|
2825
|
+
* Always renders NotificationBanner (for broadcasts), admin panel only for admins
|
|
2693
2826
|
*/
|
|
2694
2827
|
this.getComponent = () => {
|
|
2695
|
-
if (!this.isAdmin)
|
|
2828
|
+
if (!this.isAdmin) {
|
|
2829
|
+
return /* @__PURE__ */ ReactEcs5.createElement(NotificationBanner, null);
|
|
2830
|
+
}
|
|
2696
2831
|
const t = this.theme;
|
|
2697
2832
|
const tabs = [];
|
|
2698
2833
|
if (this.config.sceneTabs && this.config.sceneTabs.length > 0) {
|
|
@@ -2707,8 +2842,8 @@ var AdminPanelUIModule = class {
|
|
|
2707
2842
|
if (!tabs.find((tab) => tab.id === this.activeTab) && tabs.length > 0) {
|
|
2708
2843
|
this.activeTab = tabs[0].id;
|
|
2709
2844
|
}
|
|
2710
|
-
return /* @__PURE__ */
|
|
2711
|
-
|
|
2845
|
+
return /* @__PURE__ */ ReactEcs5.createElement(
|
|
2846
|
+
UiEntity5,
|
|
2712
2847
|
{
|
|
2713
2848
|
uiTransform: {
|
|
2714
2849
|
width: "100%",
|
|
@@ -2716,28 +2851,29 @@ var AdminPanelUIModule = class {
|
|
|
2716
2851
|
positionType: "absolute"
|
|
2717
2852
|
}
|
|
2718
2853
|
},
|
|
2719
|
-
/* @__PURE__ */
|
|
2720
|
-
|
|
2854
|
+
/* @__PURE__ */ ReactEcs5.createElement(NotificationBanner, null),
|
|
2855
|
+
/* @__PURE__ */ ReactEcs5.createElement(
|
|
2856
|
+
UiEntity5,
|
|
2721
2857
|
{
|
|
2722
2858
|
uiTransform: {
|
|
2723
2859
|
position: { right: 20 + this.s(100) + 10 + this.s(100) + 10, bottom: 10 },
|
|
2724
2860
|
positionType: "absolute"
|
|
2725
2861
|
}
|
|
2726
2862
|
},
|
|
2727
|
-
/* @__PURE__ */
|
|
2863
|
+
/* @__PURE__ */ ReactEcs5.createElement(
|
|
2728
2864
|
Button3,
|
|
2729
2865
|
{
|
|
2730
2866
|
uiTransform: { width: this.s(100), height: this.s(45) },
|
|
2731
|
-
uiBackground: { color: this.panelOpen ?
|
|
2867
|
+
uiBackground: { color: this.panelOpen ? C2.btn : C2.header },
|
|
2732
2868
|
value: this.panelOpen ? "CLOSE" : "ADMIN",
|
|
2733
2869
|
fontSize: this.s(14),
|
|
2734
|
-
color:
|
|
2870
|
+
color: C2.text,
|
|
2735
2871
|
onMouseDown: () => this.toggle()
|
|
2736
2872
|
}
|
|
2737
2873
|
)
|
|
2738
2874
|
),
|
|
2739
|
-
this.panelOpen && /* @__PURE__ */
|
|
2740
|
-
|
|
2875
|
+
this.panelOpen && /* @__PURE__ */ ReactEcs5.createElement(
|
|
2876
|
+
UiEntity5,
|
|
2741
2877
|
{
|
|
2742
2878
|
key: `admin-panel-${this.client.uiScale}`,
|
|
2743
2879
|
uiTransform: {
|
|
@@ -2748,10 +2884,10 @@ var AdminPanelUIModule = class {
|
|
|
2748
2884
|
positionType: "absolute",
|
|
2749
2885
|
flexDirection: "column"
|
|
2750
2886
|
},
|
|
2751
|
-
uiBackground: { color:
|
|
2887
|
+
uiBackground: { color: C2.bg }
|
|
2752
2888
|
},
|
|
2753
|
-
/* @__PURE__ */
|
|
2754
|
-
|
|
2889
|
+
/* @__PURE__ */ ReactEcs5.createElement(
|
|
2890
|
+
UiEntity5,
|
|
2755
2891
|
{
|
|
2756
2892
|
uiTransform: {
|
|
2757
2893
|
width: "100%",
|
|
@@ -2761,10 +2897,10 @@ var AdminPanelUIModule = class {
|
|
|
2761
2897
|
flexDirection: "row",
|
|
2762
2898
|
padding: { left: 12, right: 8 }
|
|
2763
2899
|
},
|
|
2764
|
-
uiBackground: { color:
|
|
2900
|
+
uiBackground: { color: C2.header }
|
|
2765
2901
|
},
|
|
2766
|
-
/* @__PURE__ */
|
|
2767
|
-
/* @__PURE__ */
|
|
2902
|
+
/* @__PURE__ */ ReactEcs5.createElement(Label5, { value: this.config.title || "ADMIN PANEL", fontSize: t.header, color: C2.text }),
|
|
2903
|
+
/* @__PURE__ */ ReactEcs5.createElement(
|
|
2768
2904
|
Button3,
|
|
2769
2905
|
{
|
|
2770
2906
|
uiTransform: { width: this.s(28), height: this.s(28) },
|
|
@@ -2776,9 +2912,9 @@ var AdminPanelUIModule = class {
|
|
|
2776
2912
|
}
|
|
2777
2913
|
)
|
|
2778
2914
|
),
|
|
2779
|
-
/* @__PURE__ */
|
|
2780
|
-
/* @__PURE__ */
|
|
2781
|
-
|
|
2915
|
+
/* @__PURE__ */ ReactEcs5.createElement(UiEntity5, { uiTransform: { width: "100%", height: this.s(UI_DIMENSIONS.admin.tabHeight), flexDirection: "row" } }, tabs.map((tab) => /* @__PURE__ */ ReactEcs5.createElement(this.TabBtn, { label: tab.label, tab: tab.id }))),
|
|
2916
|
+
/* @__PURE__ */ ReactEcs5.createElement(
|
|
2917
|
+
UiEntity5,
|
|
2782
2918
|
{
|
|
2783
2919
|
uiTransform: {
|
|
2784
2920
|
width: "100%",
|
|
@@ -2787,12 +2923,12 @@ var AdminPanelUIModule = class {
|
|
|
2787
2923
|
flexDirection: "column"
|
|
2788
2924
|
}
|
|
2789
2925
|
},
|
|
2790
|
-
this.activeTab === "video" && /* @__PURE__ */
|
|
2791
|
-
this.activeTab === "mod" && this.isOwner && /* @__PURE__ */
|
|
2926
|
+
this.activeTab === "video" && /* @__PURE__ */ ReactEcs5.createElement(this.VideoTab, null),
|
|
2927
|
+
this.activeTab === "mod" && this.isOwner && /* @__PURE__ */ ReactEcs5.createElement(this.ModTab, null),
|
|
2792
2928
|
this.config.sceneTabs?.map((tab) => this.activeTab === tab.id && tab.render())
|
|
2793
2929
|
),
|
|
2794
|
-
/* @__PURE__ */
|
|
2795
|
-
|
|
2930
|
+
/* @__PURE__ */ ReactEcs5.createElement(
|
|
2931
|
+
UiEntity5,
|
|
2796
2932
|
{
|
|
2797
2933
|
uiTransform: {
|
|
2798
2934
|
width: "100%",
|
|
@@ -2800,16 +2936,16 @@ var AdminPanelUIModule = class {
|
|
|
2800
2936
|
justifyContent: "center",
|
|
2801
2937
|
alignItems: "center"
|
|
2802
2938
|
},
|
|
2803
|
-
uiBackground: { color:
|
|
2939
|
+
uiBackground: { color: C2.section }
|
|
2804
2940
|
},
|
|
2805
|
-
/* @__PURE__ */
|
|
2941
|
+
/* @__PURE__ */ ReactEcs5.createElement(
|
|
2806
2942
|
Button3,
|
|
2807
2943
|
{
|
|
2808
2944
|
uiTransform: { height: this.s(24) },
|
|
2809
2945
|
uiBackground: { color: Color45.create(0, 0, 0, 0) },
|
|
2810
2946
|
value: `thestatic.tv/scene/${this.config.sceneId}`,
|
|
2811
2947
|
fontSize: t.labelSmall,
|
|
2812
|
-
color:
|
|
2948
|
+
color: C2.cyan,
|
|
2813
2949
|
onMouseDown: () => openExternalUrl3({ url: this.config.footerLink || `https://thestatic.tv/scene/${this.config.sceneId}` })
|
|
2814
2950
|
}
|
|
2815
2951
|
)
|
|
@@ -2832,7 +2968,7 @@ var AdminPanelUIModule = class {
|
|
|
2832
2968
|
};
|
|
2833
2969
|
this.baseUrl = client.getBaseUrl();
|
|
2834
2970
|
if (config.headerColor) {
|
|
2835
|
-
|
|
2971
|
+
C2.header = Color45.create(
|
|
2836
2972
|
config.headerColor.r,
|
|
2837
2973
|
config.headerColor.g,
|
|
2838
2974
|
config.headerColor.b,
|
|
@@ -2860,6 +2996,7 @@ var AdminPanelUIModule = class {
|
|
|
2860
2996
|
await this.checkAdminStatus();
|
|
2861
2997
|
await this.fetchVideoState();
|
|
2862
2998
|
this.autoPlayDefault();
|
|
2999
|
+
this.startCommandPolling();
|
|
2863
3000
|
this.log("Initialized");
|
|
2864
3001
|
}
|
|
2865
3002
|
/**
|
|
@@ -2965,6 +3102,61 @@ var AdminPanelUIModule = class {
|
|
|
2965
3102
|
this.log("Stream polling stopped");
|
|
2966
3103
|
}
|
|
2967
3104
|
}
|
|
3105
|
+
// --- Command Polling (receives broadcasts from website) ---
|
|
3106
|
+
startCommandPolling() {
|
|
3107
|
+
if (this.commandPollIntervalId !== null) return;
|
|
3108
|
+
this.commandPollIntervalId = dclSetInterval(() => {
|
|
3109
|
+
this.pollCommands();
|
|
3110
|
+
}, 5e3);
|
|
3111
|
+
this.pollCommands();
|
|
3112
|
+
this.log("Command polling started");
|
|
3113
|
+
}
|
|
3114
|
+
stopCommandPolling() {
|
|
3115
|
+
if (this.commandPollIntervalId !== null) {
|
|
3116
|
+
dclClearInterval(this.commandPollIntervalId);
|
|
3117
|
+
this.commandPollIntervalId = null;
|
|
3118
|
+
this.log("Command polling stopped");
|
|
3119
|
+
}
|
|
3120
|
+
}
|
|
3121
|
+
async pollCommands() {
|
|
3122
|
+
try {
|
|
3123
|
+
const res = await fetch(`${this.baseUrl}/scene/${this.config.sceneId}/commands`);
|
|
3124
|
+
if (!res.ok) return;
|
|
3125
|
+
const data = await res.json();
|
|
3126
|
+
const commands = data.commands || [];
|
|
3127
|
+
for (const cmd of commands) {
|
|
3128
|
+
if (cmd.timestamp <= this.lastCommandTimestamp) continue;
|
|
3129
|
+
this.lastCommandTimestamp = cmd.timestamp;
|
|
3130
|
+
if (cmd.type === "broadcast" && cmd.payload?.text) {
|
|
3131
|
+
const msg = cmd.payload.from ? `${cmd.payload.from}: ${cmd.payload.text}` : cmd.payload.text;
|
|
3132
|
+
this.log("Received broadcast:", msg);
|
|
3133
|
+
this.config.onBroadcast?.(msg);
|
|
3134
|
+
} else if (cmd.type === "clearBroadcast") {
|
|
3135
|
+
this.log("Received clearBroadcast");
|
|
3136
|
+
hideNotification();
|
|
3137
|
+
} else if ((cmd.type === "videoPlay" || cmd.type === "videoSetUrl") && cmd.payload?.url) {
|
|
3138
|
+
this.log("Received video play:", cmd.type, cmd.payload.url);
|
|
3139
|
+
this.config.onVideoPlay?.(cmd.payload.url);
|
|
3140
|
+
} else if (cmd.type === "videoStop" || cmd.type === "videoClear") {
|
|
3141
|
+
this.log("Received video stop/clear:", cmd.type);
|
|
3142
|
+
this.config.onVideoStop?.();
|
|
3143
|
+
} else if (cmd.type === "videoPlaySlot" && cmd.payload?.slot) {
|
|
3144
|
+
const slotId = cmd.payload.slot;
|
|
3145
|
+
if (cmd.payload.url) {
|
|
3146
|
+
this.log("Received videoPlaySlot with URL:", slotId, cmd.payload.url);
|
|
3147
|
+
this.config.onVideoPlay?.(cmd.payload.url);
|
|
3148
|
+
} else {
|
|
3149
|
+
this.log("Received videoPlaySlot:", slotId);
|
|
3150
|
+
this.playSlot(slotId);
|
|
3151
|
+
}
|
|
3152
|
+
} else if (this.config.onCommand) {
|
|
3153
|
+
this.log("Received command:", cmd.type, cmd.payload);
|
|
3154
|
+
this.config.onCommand(cmd.type, cmd.payload);
|
|
3155
|
+
}
|
|
3156
|
+
}
|
|
3157
|
+
} catch (err) {
|
|
3158
|
+
}
|
|
3159
|
+
}
|
|
2968
3160
|
// --- Stream API Calls ---
|
|
2969
3161
|
async fetchStreamData() {
|
|
2970
3162
|
if (this.streamFetched || !this.playerWallet) return;
|
|
@@ -3396,87 +3588,6 @@ var AdminPanelUIModule = class {
|
|
|
3396
3588
|
}
|
|
3397
3589
|
};
|
|
3398
3590
|
|
|
3399
|
-
// src/ui/ui-renderer.tsx
|
|
3400
|
-
import ReactEcs5, { ReactEcsRenderer, UiEntity as UiEntity5, Label as Label5 } from "@dcl/sdk/react-ecs";
|
|
3401
|
-
import { Color4 as Color46 } from "@dcl/sdk/math";
|
|
3402
|
-
import { engine as engine2 } from "@dcl/sdk/ecs";
|
|
3403
|
-
var notificationText = "";
|
|
3404
|
-
var notificationVisible = false;
|
|
3405
|
-
var notificationEndTime = 0;
|
|
3406
|
-
var notificationInitialized = false;
|
|
3407
|
-
function showNotification(message, durationMs = 5e3) {
|
|
3408
|
-
notificationText = message;
|
|
3409
|
-
notificationVisible = true;
|
|
3410
|
-
notificationEndTime = Date.now() + durationMs;
|
|
3411
|
-
}
|
|
3412
|
-
function initNotificationSystem() {
|
|
3413
|
-
if (notificationInitialized) return;
|
|
3414
|
-
notificationInitialized = true;
|
|
3415
|
-
engine2.addSystem(() => {
|
|
3416
|
-
if (notificationVisible && Date.now() > notificationEndTime) {
|
|
3417
|
-
notificationVisible = false;
|
|
3418
|
-
}
|
|
3419
|
-
});
|
|
3420
|
-
}
|
|
3421
|
-
function NotificationBanner() {
|
|
3422
|
-
if (!notificationVisible) return null;
|
|
3423
|
-
return /* @__PURE__ */ ReactEcs5.createElement(
|
|
3424
|
-
UiEntity5,
|
|
3425
|
-
{
|
|
3426
|
-
uiTransform: {
|
|
3427
|
-
positionType: "absolute",
|
|
3428
|
-
position: { top: 80 },
|
|
3429
|
-
width: 500,
|
|
3430
|
-
height: 60,
|
|
3431
|
-
padding: 16,
|
|
3432
|
-
alignSelf: "center",
|
|
3433
|
-
justifyContent: "center",
|
|
3434
|
-
alignItems: "center"
|
|
3435
|
-
},
|
|
3436
|
-
uiBackground: { color: Color46.create(0.1, 0.1, 0.15, 0.95) }
|
|
3437
|
-
},
|
|
3438
|
-
/* @__PURE__ */ ReactEcs5.createElement(
|
|
3439
|
-
Label5,
|
|
3440
|
-
{
|
|
3441
|
-
value: notificationText,
|
|
3442
|
-
fontSize: 18,
|
|
3443
|
-
color: Color46.create(0, 1, 1, 1),
|
|
3444
|
-
textAlign: "middle-center"
|
|
3445
|
-
}
|
|
3446
|
-
)
|
|
3447
|
-
);
|
|
3448
|
-
}
|
|
3449
|
-
function createStaticUI(client) {
|
|
3450
|
-
initNotificationSystem();
|
|
3451
|
-
return function StaticUI() {
|
|
3452
|
-
const currentScale = client.uiScale;
|
|
3453
|
-
const guideComponent = client.guideUI?.getComponent() ?? null;
|
|
3454
|
-
const chatComponent = client.chatUI?.getComponent() ?? null;
|
|
3455
|
-
const adminComponent = client.adminPanel?.getComponent() ?? null;
|
|
3456
|
-
return /* @__PURE__ */ ReactEcs5.createElement(
|
|
3457
|
-
UiEntity5,
|
|
3458
|
-
{
|
|
3459
|
-
key: `static-ui-root-${currentScale}`,
|
|
3460
|
-
uiTransform: {
|
|
3461
|
-
width: "100%",
|
|
3462
|
-
height: "100%",
|
|
3463
|
-
positionType: "absolute",
|
|
3464
|
-
flexDirection: "column",
|
|
3465
|
-
alignItems: "center"
|
|
3466
|
-
}
|
|
3467
|
-
},
|
|
3468
|
-
/* @__PURE__ */ ReactEcs5.createElement(NotificationBanner, null),
|
|
3469
|
-
guideComponent,
|
|
3470
|
-
chatComponent,
|
|
3471
|
-
adminComponent
|
|
3472
|
-
);
|
|
3473
|
-
};
|
|
3474
|
-
}
|
|
3475
|
-
function setupStaticUI(client) {
|
|
3476
|
-
const StaticUI = createStaticUI(client);
|
|
3477
|
-
ReactEcsRenderer.setUiRenderer(StaticUI);
|
|
3478
|
-
}
|
|
3479
|
-
|
|
3480
3591
|
// src/StaticTVClient.ts
|
|
3481
3592
|
import { VideoPlayer, videoEventsSystem, VideoState } from "@dcl/sdk/ecs";
|
|
3482
3593
|
import * as utils from "@dcl-sdk/utils";
|
|
@@ -3757,10 +3868,13 @@ var StaticTVClient = class {
|
|
|
3757
3868
|
*/
|
|
3758
3869
|
stopVideo() {
|
|
3759
3870
|
const screen = this.config.videoScreen;
|
|
3871
|
+
this._pendingVideoData = null;
|
|
3872
|
+
this._streamVerified = false;
|
|
3873
|
+
this._clearVerificationTimeout();
|
|
3874
|
+
if (this.guideUI) {
|
|
3875
|
+
this.guideUI.currentVideoId = null;
|
|
3876
|
+
}
|
|
3760
3877
|
if (screen !== void 0) {
|
|
3761
|
-
if (this.guideUI) {
|
|
3762
|
-
this.guideUI.currentVideoId = null;
|
|
3763
|
-
}
|
|
3764
3878
|
const fallbackUrl = this.config.fallbackVideoUrl;
|
|
3765
3879
|
const fallbackDisabled = fallbackUrl === "";
|
|
3766
3880
|
if (fallbackDisabled) {
|
|
@@ -3916,20 +4030,60 @@ var StaticTVClient = class {
|
|
|
3916
4030
|
}
|
|
3917
4031
|
/**
|
|
3918
4032
|
* Play video with stream verification for live content
|
|
4033
|
+
* Works with both videoScreen (SDK-managed) and onVideoPlay (user-managed) modes.
|
|
3919
4034
|
* @internal
|
|
3920
4035
|
*/
|
|
3921
4036
|
_playVideoWithVerification(video, isLiveStream) {
|
|
3922
4037
|
const screen = this.config.videoScreen;
|
|
4038
|
+
const hasCallback = this.config.onVideoPlay !== void 0;
|
|
4039
|
+
this.log(`Playing video: ${video.src} (live: ${isLiveStream}, screen: ${screen !== void 0}, callback: ${hasCallback})`);
|
|
4040
|
+
this._currentVideoUrl = video.src;
|
|
4041
|
+
this._clearVerificationTimeout();
|
|
4042
|
+
this._streamVerified = false;
|
|
3923
4043
|
if (screen !== void 0) {
|
|
3924
|
-
this.log(`Playing video: ${video.src} (live: ${isLiveStream})`);
|
|
3925
|
-
this._currentVideoUrl = video.src;
|
|
3926
4044
|
this._playVideoInternal(video.src, false, isLiveStream);
|
|
3927
|
-
if (this.guideUI) {
|
|
3928
|
-
this.guideUI.currentVideoId = video.id;
|
|
3929
|
-
}
|
|
3930
4045
|
}
|
|
3931
|
-
if (
|
|
4046
|
+
if (hasCallback) {
|
|
3932
4047
|
this.config.onVideoPlay(video.src);
|
|
4048
|
+
if (isLiveStream) {
|
|
4049
|
+
this._startCallbackVerification(video);
|
|
4050
|
+
}
|
|
4051
|
+
}
|
|
4052
|
+
if (this.guideUI) {
|
|
4053
|
+
this.guideUI.currentVideoId = video.id;
|
|
4054
|
+
}
|
|
4055
|
+
}
|
|
4056
|
+
/**
|
|
4057
|
+
* Start stream verification for callback-based video playback
|
|
4058
|
+
* Shows CONNECTING state and triggers fallback if verification times out
|
|
4059
|
+
* @internal
|
|
4060
|
+
*/
|
|
4061
|
+
_startCallbackVerification(video) {
|
|
4062
|
+
this.showNotification(`Connecting to ${video.name}...`, 6e3);
|
|
4063
|
+
this._verificationTimeoutId = utils.timers.setTimeout(() => {
|
|
4064
|
+
if (!this._streamVerified && this._pendingVideoData) {
|
|
4065
|
+
this.log(`Stream verification timeout (callback mode): ${video.name}`);
|
|
4066
|
+
this._handleStreamOffline();
|
|
4067
|
+
}
|
|
4068
|
+
}, 5e3);
|
|
4069
|
+
}
|
|
4070
|
+
/**
|
|
4071
|
+
* Call this to confirm that a video stream is playing successfully.
|
|
4072
|
+
* Use this when you're managing video playback yourself (onVideoPlay callback).
|
|
4073
|
+
*
|
|
4074
|
+
* @example
|
|
4075
|
+
* ```typescript
|
|
4076
|
+
* // In your video player's onReady or similar event:
|
|
4077
|
+
* videoPlayer.events.on('playing', () => {
|
|
4078
|
+
* staticTV.confirmVideoPlaying()
|
|
4079
|
+
* })
|
|
4080
|
+
* ```
|
|
4081
|
+
*/
|
|
4082
|
+
confirmVideoPlaying() {
|
|
4083
|
+
if (this._pendingVideoData && !this._streamVerified) {
|
|
4084
|
+
this._streamVerified = true;
|
|
4085
|
+
this._clearVerificationTimeout();
|
|
4086
|
+
this.log(`Stream confirmed playing: ${this._pendingVideoData.name}`);
|
|
3933
4087
|
}
|
|
3934
4088
|
}
|
|
3935
4089
|
/**
|
|
@@ -4203,11 +4357,13 @@ export {
|
|
|
4203
4357
|
InteractionsModule,
|
|
4204
4358
|
KEY_TYPE_CHANNEL,
|
|
4205
4359
|
KEY_TYPE_SCENE,
|
|
4360
|
+
NotificationBanner,
|
|
4206
4361
|
SessionModule,
|
|
4207
4362
|
StaticTVClient,
|
|
4208
4363
|
fetchUserData,
|
|
4209
4364
|
getPlayerDisplayName,
|
|
4210
4365
|
getPlayerWallet,
|
|
4366
|
+
hideNotification,
|
|
4211
4367
|
setupStaticUI,
|
|
4212
4368
|
showNotification
|
|
4213
4369
|
};
|