@dcl-regenesislabs/web-editor 0.0.0-stage → 0.1.0
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/editor.css +1 -0
- package/editor.js +33891 -0
- package/package.json +8 -4
- package/prefabs/admin-tools/composite.json +77 -0
- package/prefabs/admin-tools/data.json +28 -0
- package/prefabs/admin-tools/icons/admin-panel-control-button.png +0 -0
- package/prefabs/admin-tools/icons/admin-panel-moderation-control-button.png +0 -0
- package/prefabs/admin-tools/icons/admin-panel-rewards-control-button.png +0 -0
- package/prefabs/admin-tools/icons/admin-panel-smart-item-control-button.png +0 -0
- package/prefabs/admin-tools/icons/admin-panel-text-announcement-control-button.png +0 -0
- package/prefabs/admin-tools/icons/admin-panel-video-control-button.png +0 -0
- package/prefabs/admin-tools/icons/admin-tool-background.png +0 -0
- package/prefabs/admin-tools/icons/announcements/text-announcement-chat-message.png +0 -0
- package/prefabs/admin-tools/icons/announcements/text-announcement-check.png +0 -0
- package/prefabs/admin-tools/icons/announcements/text-announcement-close-button.png +0 -0
- package/prefabs/admin-tools/icons/moderation/admin-panel-verified-user.png +0 -0
- package/prefabs/admin-tools/icons/moderation/ban.png +0 -0
- package/prefabs/admin-tools/icons/moderation/chevron-back.png +0 -0
- package/prefabs/admin-tools/icons/moderation/chevron-forward.png +0 -0
- package/prefabs/admin-tools/icons/moderation/close.png +0 -0
- package/prefabs/admin-tools/icons/moderation/error.png +0 -0
- package/prefabs/admin-tools/icons/moderation/person-outline.png +0 -0
- package/prefabs/admin-tools/icons/moderation-control-icon.png +0 -0
- package/prefabs/admin-tools/icons/rewards/close.png +0 -0
- package/prefabs/admin-tools/icons/rewards/send.png +0 -0
- package/prefabs/admin-tools/icons/rewards-control.png +0 -0
- package/prefabs/admin-tools/icons/smart-item-control.png +0 -0
- package/prefabs/admin-tools/icons/text-announcement-control.png +0 -0
- package/prefabs/admin-tools/icons/video/chevron-down.png +0 -0
- package/prefabs/admin-tools/icons/video/chevron-up.png +0 -0
- package/prefabs/admin-tools/icons/video/copy-to-clipboard.png +0 -0
- package/prefabs/admin-tools/icons/video/error.png +0 -0
- package/prefabs/admin-tools/icons/video/eye-off.png +0 -0
- package/prefabs/admin-tools/icons/video/eye.png +0 -0
- package/prefabs/admin-tools/icons/video/help.png +0 -0
- package/prefabs/admin-tools/icons/video/info.png +0 -0
- package/prefabs/admin-tools/icons/video/person-outline.png +0 -0
- package/prefabs/admin-tools/icons/video/star.png +0 -0
- package/prefabs/admin-tools/icons/video/video-control-dcl-cast.png +0 -0
- package/prefabs/admin-tools/icons/video/video-control-live.png +0 -0
- package/prefabs/admin-tools/icons/video/video-control-loop.png +0 -0
- package/prefabs/admin-tools/icons/video/video-control-mute.png +0 -0
- package/prefabs/admin-tools/icons/video/video-control-pause-button.png +0 -0
- package/prefabs/admin-tools/icons/video/video-control-play-button.png +0 -0
- package/prefabs/admin-tools/icons/video/video-control-video-icon.png +0 -0
- package/prefabs/admin-tools/icons/video/video-control-volume-minus-button.png +0 -0
- package/prefabs/admin-tools/icons/video/video-control-volume-plus-button.png +0 -0
- package/prefabs/admin-tools/icons/video-control.png +0 -0
- package/prefabs/admin-tools/scripts/actions.ts +206 -0
- package/prefabs/admin-tools/scripts/admin.tsx +253 -0
- package/prefabs/admin-tools/scripts/api.ts +125 -0
- package/prefabs/admin-tools/scripts/components.ts +190 -0
- package/prefabs/admin-tools/scripts/icons.ts +53 -0
- package/prefabs/admin-tools/scripts/message-bus.ts +297 -0
- package/prefabs/admin-tools/scripts/state.ts +69 -0
- package/prefabs/admin-tools/scripts/tabs/Moderation.tsx +155 -0
- package/prefabs/admin-tools/scripts/tabs/Rewards.tsx +136 -0
- package/prefabs/admin-tools/scripts/tabs/SmartItemActions.tsx +167 -0
- package/prefabs/admin-tools/scripts/tabs/TextAnnouncements.tsx +195 -0
- package/prefabs/admin-tools/scripts/tabs/VideoControl.tsx +156 -0
- package/prefabs/admin-tools/scripts/tabs/announcements/Overlay.tsx +94 -0
- package/prefabs/admin-tools/scripts/tabs/announcements/icons.ts +15 -0
- package/prefabs/admin-tools/scripts/tabs/announcements/state.ts +71 -0
- package/prefabs/admin-tools/scripts/tabs/announcements/ui.tsx +37 -0
- package/prefabs/admin-tools/scripts/tabs/moderation/AddUserInput.tsx +184 -0
- package/prefabs/admin-tools/scripts/tabs/moderation/RemoveAdminConfirmation.tsx +93 -0
- package/prefabs/admin-tools/scripts/tabs/moderation/UsersList.tsx +228 -0
- package/prefabs/admin-tools/scripts/tabs/moderation/api.ts +35 -0
- package/prefabs/admin-tools/scripts/tabs/moderation/icons.ts +23 -0
- package/prefabs/admin-tools/scripts/tabs/moderation/kick.ts +95 -0
- package/prefabs/admin-tools/scripts/tabs/moderation/state.ts +69 -0
- package/prefabs/admin-tools/scripts/tabs/moderation/ui.tsx +172 -0
- package/prefabs/admin-tools/scripts/tabs/moderation/utils.ts +88 -0
- package/prefabs/admin-tools/scripts/tabs/rewards/Button.tsx +52 -0
- package/prefabs/admin-tools/scripts/tabs/rewards/Captcha.tsx +88 -0
- package/prefabs/admin-tools/scripts/tabs/rewards/api.ts +138 -0
- package/prefabs/admin-tools/scripts/tabs/rewards/claim.ts +99 -0
- package/prefabs/admin-tools/scripts/tabs/rewards/controller.ts +103 -0
- package/prefabs/admin-tools/scripts/tabs/rewards/icons.ts +13 -0
- package/prefabs/admin-tools/scripts/tabs/rewards/state.ts +32 -0
- package/prefabs/admin-tools/scripts/tabs/smart-items/selection.ts +90 -0
- package/prefabs/admin-tools/scripts/tabs/video/DclCast.tsx +226 -0
- package/prefabs/admin-tools/scripts/tabs/video/LiveStream.tsx +284 -0
- package/prefabs/admin-tools/scripts/tabs/video/SpeakerShowcase.tsx +112 -0
- package/prefabs/admin-tools/scripts/tabs/video/VideoUrl.tsx +107 -0
- package/prefabs/admin-tools/scripts/tabs/video/Volume.tsx +69 -0
- package/prefabs/admin-tools/scripts/tabs/video/api.ts +172 -0
- package/prefabs/admin-tools/scripts/tabs/video/controls.ts +108 -0
- package/prefabs/admin-tools/scripts/tabs/video/icons.ts +59 -0
- package/prefabs/admin-tools/scripts/tabs/video/speakers.ts +43 -0
- package/prefabs/admin-tools/scripts/tabs/video/state.ts +82 -0
- package/prefabs/admin-tools/scripts/tabs/video/ui.tsx +243 -0
- package/prefabs/admin-tools/scripts/types.ts +46 -0
- package/prefabs/admin-tools/scripts/ui.tsx +122 -0
- package/prefabs/admin-tools/thumbnail.png +0 -0
- package/prefabs/announcer/ai.md +76 -0
- package/prefabs/announcer/composite.json +31 -0
- package/prefabs/announcer/data.json +35 -0
- package/prefabs/announcer/scripts/announcer.tsx +79 -0
- package/prefabs/announcer/scripts/pure/toast.ts +30 -0
- package/prefabs/announcer/thumbnail.png +0 -0
- package/prefabs/black-chair/HighBackChair.glb +0 -0
- package/prefabs/black-chair/composite.json +74 -0
- package/prefabs/black-chair/data.json +30 -0
- package/prefabs/black-chair/scripts/seat.ts +191 -0
- package/prefabs/black-chair/thumbnail.png +0 -0
- package/prefabs/catalog.json +1 -0
- package/prefabs/classic-bench/Bench_01.glb +0 -0
- package/prefabs/classic-bench/composite.json +100 -0
- package/prefabs/classic-bench/data.json +34 -0
- package/prefabs/classic-bench/file1.png +0 -0
- package/prefabs/classic-bench/scripts/seat.ts +191 -0
- package/prefabs/classic-bench/thumbnail.png +0 -0
- package/prefabs/classic-bench-armrests/Bench 1.glb +0 -0
- package/prefabs/classic-bench-armrests/composite.json +100 -0
- package/prefabs/classic-bench-armrests/data.json +30 -0
- package/prefabs/classic-bench-armrests/scripts/seat.ts +191 -0
- package/prefabs/classic-bench-armrests/thumbnail.png +0 -0
- package/prefabs/classroom-chair/Chair_02.glb +0 -0
- package/prefabs/classroom-chair/composite.json +74 -0
- package/prefabs/classroom-chair/data.json +34 -0
- package/prefabs/classroom-chair/file1.png +0 -0
- package/prefabs/classroom-chair/scripts/seat.ts +191 -0
- package/prefabs/classroom-chair/thumbnail.png +0 -0
- package/prefabs/court-chair/Chair_Wood_01.glb +0 -0
- package/prefabs/court-chair/FanstasyPack_TX.png +0 -0
- package/prefabs/court-chair/composite.json +74 -0
- package/prefabs/court-chair/data.json +34 -0
- package/prefabs/court-chair/scripts/seat.ts +191 -0
- package/prefabs/court-chair/thumbnail.png +0 -0
- package/prefabs/curved-couch/CurvedCouch.glb +0 -0
- package/prefabs/curved-couch/composite.json +100 -0
- package/prefabs/curved-couch/data.json +30 -0
- package/prefabs/curved-couch/scripts/seat.ts +191 -0
- package/prefabs/curved-couch/thumbnail.png +0 -0
- package/prefabs/game-flow/ai.md +94 -0
- package/prefabs/game-flow/composite.json +45 -0
- package/prefabs/game-flow/data.json +27 -0
- package/prefabs/game-flow/scripts/game-flow.ts +168 -0
- package/prefabs/game-flow/scripts/pure/flow.ts +185 -0
- package/prefabs/game-flow/thumbnail.png +0 -0
- package/prefabs/health-respawn/ai.md +76 -0
- package/prefabs/health-respawn/composite.json +31 -0
- package/prefabs/health-respawn/data.json +38 -0
- package/prefabs/health-respawn/scripts/health-respawn.ts +98 -0
- package/prefabs/health-respawn/scripts/health.ts +22 -0
- package/prefabs/health-respawn/scripts/pure/health.ts +60 -0
- package/prefabs/health-respawn/thumbnail.png +0 -0
- package/prefabs/high-stool/HighStool.glb +0 -0
- package/prefabs/high-stool/composite.json +74 -0
- package/prefabs/high-stool/data.json +30 -0
- package/prefabs/high-stool/scripts/seat.ts +191 -0
- package/prefabs/high-stool/thumbnail.png +0 -0
- package/prefabs/large-couch/ThreeSeater_Couch.glb +0 -0
- package/prefabs/large-couch/composite.json +100 -0
- package/prefabs/large-couch/data.json +30 -0
- package/prefabs/large-couch/scripts/seat.ts +191 -0
- package/prefabs/large-couch/thumbnail.png +0 -0
- package/prefabs/leaderboard/ai.md +75 -0
- package/prefabs/leaderboard/board-panel.glb +0 -0
- package/prefabs/leaderboard/composite.json +82 -0
- package/prefabs/leaderboard/data.json +35 -0
- package/prefabs/leaderboard/scripts/leaderboard.ts +66 -0
- package/prefabs/leaderboard/scripts/pure/board.ts +71 -0
- package/prefabs/leaderboard/thumbnail.png +0 -0
- package/prefabs/loveseat/Couch_01.glb +0 -0
- package/prefabs/loveseat/composite.json +100 -0
- package/prefabs/loveseat/data.json +34 -0
- package/prefabs/loveseat/file1.png +0 -0
- package/prefabs/loveseat/scripts/seat.ts +191 -0
- package/prefabs/loveseat/thumbnail.png +0 -0
- package/prefabs/modern-sofa/ModernSofa.glb +0 -0
- package/prefabs/modern-sofa/composite.json +100 -0
- package/prefabs/modern-sofa/data.json +30 -0
- package/prefabs/modern-sofa/scripts/seat.ts +191 -0
- package/prefabs/modern-sofa/thumbnail.png +0 -0
- package/prefabs/outdoor-chair/Chair_07.glb +0 -0
- package/prefabs/outdoor-chair/composite.json +74 -0
- package/prefabs/outdoor-chair/data.json +34 -0
- package/prefabs/outdoor-chair/file1.png +0 -0
- package/prefabs/outdoor-chair/scripts/seat.ts +191 -0
- package/prefabs/outdoor-chair/thumbnail.png +0 -0
- package/prefabs/rustic-bench/Bench_01.glb +0 -0
- package/prefabs/rustic-bench/PiratesPack_TX.png.png +0 -0
- package/prefabs/rustic-bench/composite.json +100 -0
- package/prefabs/rustic-bench/data.json +34 -0
- package/prefabs/rustic-bench/scripts/seat.ts +191 -0
- package/prefabs/rustic-bench/thumbnail.png +0 -0
- package/prefabs/rustic-round-stool/Chairwood_01.glb +0 -0
- package/prefabs/rustic-round-stool/PiratesPack_TX.png.png +0 -0
- package/prefabs/rustic-round-stool/composite.json +74 -0
- package/prefabs/rustic-round-stool/data.json +34 -0
- package/prefabs/rustic-round-stool/scripts/seat.ts +191 -0
- package/prefabs/rustic-round-stool/thumbnail.png +0 -0
- package/prefabs/rustic-square-stool/Chairwood_02.glb +0 -0
- package/prefabs/rustic-square-stool/PiratesPack_TX.png.png +0 -0
- package/prefabs/rustic-square-stool/composite.json +74 -0
- package/prefabs/rustic-square-stool/data.json +34 -0
- package/prefabs/rustic-square-stool/scripts/seat.ts +191 -0
- package/prefabs/rustic-square-stool/thumbnail.png +0 -0
- package/prefabs/server-clock/ai.md +67 -0
- package/prefabs/server-clock/composite.json +45 -0
- package/prefabs/server-clock/data.json +24 -0
- package/prefabs/server-clock/scripts/clock-hud.tsx +55 -0
- package/prefabs/server-clock/scripts/server-clock.ts +71 -0
- package/prefabs/server-clock/thumbnail.png +0 -0
- package/prefabs/simple-chair/Chair_03.glb +0 -0
- package/prefabs/simple-chair/composite.json +74 -0
- package/prefabs/simple-chair/data.json +34 -0
- package/prefabs/simple-chair/file1.png +0 -0
- package/prefabs/simple-chair/scripts/seat.ts +191 -0
- package/prefabs/simple-chair/thumbnail.png +0 -0
- package/prefabs/sit-spot/composite.json +45 -0
- package/prefabs/sit-spot/data.json +30 -0
- package/prefabs/sit-spot/scripts/seat.ts +191 -0
- package/prefabs/sit-spot/thumbnail.png +0 -0
- package/prefabs/sit-spot-edge/composite.json +42 -0
- package/prefabs/sit-spot-edge/data.json +32 -0
- package/prefabs/sit-spot-edge/emotes/Sit_Edge1_emote.glb +0 -0
- package/prefabs/sit-spot-edge/emotes/Sit_Edge2_emote.glb +0 -0
- package/prefabs/sit-spot-edge/scripts/seat.ts +191 -0
- package/prefabs/sit-spot-edge/thumbnail.png +0 -0
- package/prefabs/small-couch/TwoSeater_Couch.glb +0 -0
- package/prefabs/small-couch/composite.json +100 -0
- package/prefabs/small-couch/data.json +30 -0
- package/prefabs/small-couch/scripts/seat.ts +191 -0
- package/prefabs/small-couch/thumbnail.png +0 -0
- package/prefabs/spawner/ai.md +109 -0
- package/prefabs/spawner/composite.json +73 -0
- package/prefabs/spawner/data.json +22 -0
- package/prefabs/spawner/scripts/spawner.ts +380 -0
- package/prefabs/spawner/thumbnail.png +0 -0
- package/prefabs/steampunk-bench/Steampunk Bench.glb +0 -0
- package/prefabs/steampunk-bench/composite.json +100 -0
- package/prefabs/steampunk-bench/data.json +30 -0
- package/prefabs/steampunk-bench/scripts/seat.ts +191 -0
- package/prefabs/steampunk-bench/thumbnail.png +0 -0
- package/prefabs/steampunk-chair/Steampunk Chair.glb +0 -0
- package/prefabs/steampunk-chair/composite.json +74 -0
- package/prefabs/steampunk-chair/data.json +30 -0
- package/prefabs/steampunk-chair/scripts/seat.ts +191 -0
- package/prefabs/steampunk-chair/thumbnail.png +0 -0
- package/prefabs/tall-stool/Stool_D.glb +0 -0
- package/prefabs/tall-stool/composite.json +74 -0
- package/prefabs/tall-stool/data.json +30 -0
- package/prefabs/tall-stool/scripts/seat.ts +191 -0
- package/prefabs/tall-stool/thumbnail.png +0 -0
- package/prefabs/trigger-zone/ai.md +115 -0
- package/prefabs/trigger-zone/composite.json +52 -0
- package/prefabs/trigger-zone/data.json +31 -0
- package/prefabs/trigger-zone/scripts/trigger-zone.ts +89 -0
- package/prefabs/trigger-zone/thumbnail.png +0 -0
- package/prefabs/video-screen/composite.json +98 -0
- package/prefabs/video-screen/data.json +21 -0
- package/prefabs/video-screen/thumbnail.png +0 -0
- package/prefabs/video-screen/video_player.glb +0 -0
- package/prefabs/wooden-chair/Chair 1.glb +0 -0
- package/prefabs/wooden-chair/composite.json +74 -0
- package/prefabs/wooden-chair/data.json +30 -0
- package/prefabs/wooden-chair/scripts/seat.ts +191 -0
- package/prefabs/wooden-chair/thumbnail.png +0 -0
- package/prefabs/wooden-chair-armrests/Chair 3.glb +0 -0
- package/prefabs/wooden-chair-armrests/composite.json +74 -0
- package/prefabs/wooden-chair-armrests/data.json +30 -0
- package/prefabs/wooden-chair-armrests/scripts/seat.ts +191 -0
- package/prefabs/wooden-chair-armrests/thumbnail.png +0 -0
- package/scene/about +17 -0
- package/scene/bafkreias2w4xuqaic6sdcvblrisayi6xg7drfowzpt5ubjkmrk3mx6czc4 +1 -0
- package/scene/bafkreiby2gmthtauf7cckttphmhpecsueyypi2hzlke4lcodg7fm4cm2sq +23 -0
- package/scene/bafkreidhwqwajqk4nsuffef5fkdrgmp5ql6vnn2knpqsuqalyosv5o6lk4 +1 -0
- package/scene/bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku +0 -0
- package/scene/bafybeihw3xlbff4sf5sc3kvmlmlwf2visnty5lfymawlunzt5vrkp5fd7u +90 -0
- package/web-build/esbuild.wasm +0 -0
- package/web-build/index.js +3 -0
- package/web-build/sdk-snapshot.json +1 -0
- package/web-build/worker.js +701 -0
- package/README.md +0 -3
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "493daede-2afd-4c10-9c0d-6aefb25629a8",
|
|
3
|
+
"name": "Leaderboard",
|
|
4
|
+
"description": "Shows one of your game's boards — point it at the game.state key your game writes the rows to. Works with: Game Flow.",
|
|
5
|
+
"category": "custom",
|
|
6
|
+
"group": "Multiplayer Server",
|
|
7
|
+
"tags": [
|
|
8
|
+
"multiplayer",
|
|
9
|
+
"server",
|
|
10
|
+
"leaderboard",
|
|
11
|
+
"score",
|
|
12
|
+
"ranking",
|
|
13
|
+
"board"
|
|
14
|
+
],
|
|
15
|
+
"requiresSdk": "auth-server",
|
|
16
|
+
"drivenBy": {
|
|
17
|
+
"rule": "This panel only paints what it reads — the server writes the rows into the synced state key named in Board Key, and every client draws them in order.",
|
|
18
|
+
"code": "game.setState({ leaderboard: [{ player, score }] })",
|
|
19
|
+
"next": "Press New script below and write that line inside the isServer() block it comes with, using the same key you set in Board Key above."
|
|
20
|
+
},
|
|
21
|
+
"version": "1.1.0",
|
|
22
|
+
"changelog": [
|
|
23
|
+
{
|
|
24
|
+
"version": "1.0.0",
|
|
25
|
+
"notes": "Initial release: a panel that reads the game.state key you name in boardKey and paints its top rows, so the board a Script keeps is the board every player sees and a late joiner gets it from the snapshot."
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"version": "1.1.0",
|
|
29
|
+
"notes": "The placed panel's Script card now shows the setState line that writes the rows it paints, under its own settings."
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"origin": {
|
|
33
|
+
"source": "builtin"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// A board on a panel. It reads one `game.state` key and paints it — nothing
|
|
2
|
+
// here decides a score, and nothing here stores one. The server writes the rows
|
|
3
|
+
// (see ai.md in this folder for the idiom); two boards pointed at two keys are
|
|
4
|
+
// two independent boards in one scene, and two pointed at the same key show the
|
|
5
|
+
// same thing on both walls.
|
|
6
|
+
//
|
|
7
|
+
// The panel is ordinary scene content: swap board-panel.glb for your own model
|
|
8
|
+
// and keep (or restyle) the text child — the script writes only its `text`, so
|
|
9
|
+
// font, size and colour stay exactly as authored.
|
|
10
|
+
import { TextShape, Transform, engine, type Entity } from '@dcl/sdk/ecs'
|
|
11
|
+
import { isServer } from '@dcl/sdk/network'
|
|
12
|
+
import { game } from '~runtime/game'
|
|
13
|
+
import { boardRows, clampRows, renderPanel } from './pure/board'
|
|
14
|
+
|
|
15
|
+
const EMPTY = 'Nothing to show yet — set the board key the server writes to.'
|
|
16
|
+
|
|
17
|
+
export class Leaderboard {
|
|
18
|
+
private panel: Entity | null = null
|
|
19
|
+
private painted = ''
|
|
20
|
+
|
|
21
|
+
constructor(
|
|
22
|
+
public src: string,
|
|
23
|
+
public entity: Entity,
|
|
24
|
+
/** The panel's title. */
|
|
25
|
+
public title: string = 'Leaderboard',
|
|
26
|
+
/** The game.state key this board shows. The server writes the rows there. */
|
|
27
|
+
public boardKey: string = 'leaderboard',
|
|
28
|
+
/** Which score wins: highest keeps points, lowest keeps best times. */
|
|
29
|
+
public sort: 'desc' | 'asc' = 'desc',
|
|
30
|
+
/** How many places the panel lists. */
|
|
31
|
+
public rows: number = 8
|
|
32
|
+
) {}
|
|
33
|
+
|
|
34
|
+
start(): void {
|
|
35
|
+
if (isServer()) { return }
|
|
36
|
+
this.panel = this.findPanel()
|
|
37
|
+
game.onStateChange(() => this.repaint())
|
|
38
|
+
this.repaint()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private repaint(): void {
|
|
42
|
+
this.paint(
|
|
43
|
+
renderPanel(this.title, boardRows(game.state[this.boardKey], this.sort, clampRows(this.rows)), this.sort, EMPTY)
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// The text lives on a child so the model can be replaced without touching it.
|
|
48
|
+
private findPanel(): Entity {
|
|
49
|
+
for (const [entity, transform] of engine.getEntitiesWith(Transform)) {
|
|
50
|
+
if (transform.parent === this.entity && TextShape.getOrNull(entity) !== null) return entity
|
|
51
|
+
}
|
|
52
|
+
return this.entity
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private paint(text: string): void {
|
|
56
|
+
const panel = this.panel
|
|
57
|
+
if (panel === null || text === this.painted) return
|
|
58
|
+
this.painted = text
|
|
59
|
+
const shape = TextShape.getMutableOrNull(panel)
|
|
60
|
+
if (shape !== null) {
|
|
61
|
+
shape.text = text
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
TextShape.createOrReplace(panel, { text, fontSize: 0.8 })
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// The board's reading and rendering, with no SDK and no I/O.
|
|
2
|
+
//
|
|
3
|
+
// A Leaderboard is a pure reader: the server writes rows into a `game.state` key
|
|
4
|
+
// and this turns them into panel text. Creators name those fields themselves —
|
|
5
|
+
// one game writes `{ player, seconds }`, the next `{ p, pts }` — so a row is
|
|
6
|
+
// anything with a player-ish string and a number, and anything else is skipped
|
|
7
|
+
// rather than painted as [object Object].
|
|
8
|
+
|
|
9
|
+
export type BoardSort = 'desc' | 'asc'
|
|
10
|
+
|
|
11
|
+
export interface BoardRow {
|
|
12
|
+
rank: number
|
|
13
|
+
player: string
|
|
14
|
+
score: number
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const PLAYER_FIELDS = ['player', 'p', 'address', 'wallet', 'name']
|
|
18
|
+
const SCORE_FIELDS = ['score', 'points', 'pts', 'value', 'seconds', 'time', 'best']
|
|
19
|
+
|
|
20
|
+
export const MAX_ROWS = 25
|
|
21
|
+
|
|
22
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
23
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Wallets are long; a board row reads better with the tail. */
|
|
27
|
+
export function shortName(player: string): string {
|
|
28
|
+
return player.startsWith('0x') && player.length > 10 ? `${player.slice(0, 6)}…${player.slice(-4)}` : player
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Whole seconds as m:ss — how an 'asc' board's times want to read. */
|
|
32
|
+
export function formatScore(score: number, sort: BoardSort): string {
|
|
33
|
+
if (sort === 'desc') return `${Math.round(score)}`
|
|
34
|
+
const total = Math.max(0, Math.floor(score))
|
|
35
|
+
const rest = total % 60
|
|
36
|
+
return `${Math.floor(total / 60)}:${rest < 10 ? '0' : ''}${rest}`
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function clampRows(value: number): number {
|
|
40
|
+
if (!Number.isFinite(value)) return 8
|
|
41
|
+
return Math.min(MAX_ROWS, Math.max(1, Math.round(value)))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The visible rows of whatever sits under the board key. Sorting here rather than
|
|
46
|
+
* trusting the writer's order is what lets one key feed a "highest wins" board and
|
|
47
|
+
* a "lowest wins" board at once.
|
|
48
|
+
*/
|
|
49
|
+
export function boardRows(value: unknown, sort: BoardSort, limit: number): BoardRow[] {
|
|
50
|
+
if (!Array.isArray(value)) return []
|
|
51
|
+
const rows: { player: string; score: number }[] = []
|
|
52
|
+
for (const item of value) {
|
|
53
|
+
if (!isRecord(item)) continue
|
|
54
|
+
const playerKey = PLAYER_FIELDS.find((key) => typeof item[key] === 'string' && item[key] !== '')
|
|
55
|
+
const scoreKey = SCORE_FIELDS.find((key) => typeof item[key] === 'number' && Number.isFinite(item[key]))
|
|
56
|
+
if (playerKey === undefined || scoreKey === undefined) continue
|
|
57
|
+
rows.push({ player: String(item[playerKey]), score: Number(item[scoreKey]) })
|
|
58
|
+
}
|
|
59
|
+
rows.sort((a, b) => (sort === 'desc' ? b.score - a.score : a.score - b.score))
|
|
60
|
+
return rows.slice(0, clampRows(limit)).map((row, index) => ({ rank: index + 1, ...row }))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function renderPanel(title: string, rows: BoardRow[], sort: BoardSort, placeholder: string): string {
|
|
64
|
+
const lines = [title.trim().toUpperCase(), '']
|
|
65
|
+
if (rows.length === 0) {
|
|
66
|
+
lines.push(placeholder)
|
|
67
|
+
return lines.join('\n')
|
|
68
|
+
}
|
|
69
|
+
for (const row of rows) lines.push(`${row.rank}. ${shortName(row.player)} ${formatScore(row.score, sort)}`)
|
|
70
|
+
return lines.join('\n')
|
|
71
|
+
}
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"components": [
|
|
4
|
+
{
|
|
5
|
+
"name": "core::GltfContainer",
|
|
6
|
+
"data": {
|
|
7
|
+
"0": {
|
|
8
|
+
"json": {
|
|
9
|
+
"src": "{assetPath}/Couch_01.glb",
|
|
10
|
+
"visibleMeshesCollisionMask": 0,
|
|
11
|
+
"invisibleMeshesCollisionMask": 3
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "core-schema::Name",
|
|
18
|
+
"data": {
|
|
19
|
+
"0": {
|
|
20
|
+
"json": {
|
|
21
|
+
"value": "Loveseat"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"513": {
|
|
25
|
+
"json": {
|
|
26
|
+
"value": "Sit Spot 1"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"514": {
|
|
30
|
+
"json": {
|
|
31
|
+
"value": "Sit Spot 2"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "core::Transform",
|
|
38
|
+
"data": {
|
|
39
|
+
"513": {
|
|
40
|
+
"json": {
|
|
41
|
+
"position": {
|
|
42
|
+
"x": -0.79,
|
|
43
|
+
"y": 0.08,
|
|
44
|
+
"z": 0.56
|
|
45
|
+
},
|
|
46
|
+
"rotation": {
|
|
47
|
+
"x": 0,
|
|
48
|
+
"y": -0.7071067690849304,
|
|
49
|
+
"z": 0,
|
|
50
|
+
"w": 0.7071067690849304
|
|
51
|
+
},
|
|
52
|
+
"scale": {
|
|
53
|
+
"x": 1,
|
|
54
|
+
"y": 1,
|
|
55
|
+
"z": 1
|
|
56
|
+
},
|
|
57
|
+
"parent": 0
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"514": {
|
|
61
|
+
"json": {
|
|
62
|
+
"position": {
|
|
63
|
+
"x": -0.79,
|
|
64
|
+
"y": 0.08,
|
|
65
|
+
"z": -0.4
|
|
66
|
+
},
|
|
67
|
+
"rotation": {
|
|
68
|
+
"x": 0,
|
|
69
|
+
"y": -0.7071067690849304,
|
|
70
|
+
"z": 0,
|
|
71
|
+
"w": 0.7071067690849304
|
|
72
|
+
},
|
|
73
|
+
"scale": {
|
|
74
|
+
"x": 1,
|
|
75
|
+
"y": 1,
|
|
76
|
+
"z": 1
|
|
77
|
+
},
|
|
78
|
+
"parent": 0
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"name": "asset-packs::Script",
|
|
85
|
+
"data": {
|
|
86
|
+
"0": {
|
|
87
|
+
"json": {
|
|
88
|
+
"value": [
|
|
89
|
+
{
|
|
90
|
+
"path": "{assetPath}/scripts/seat.ts",
|
|
91
|
+
"priority": 0,
|
|
92
|
+
"layout": "{\"params\":{},\"actions\":[]}"
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "78050d8f-ee51-4db7-b060-14e7a0b48939",
|
|
3
|
+
"name": "Loveseat",
|
|
4
|
+
"description": "A two-seat sofa. Players can sit at either end.",
|
|
5
|
+
"category": "custom",
|
|
6
|
+
"tags": [
|
|
7
|
+
"seat",
|
|
8
|
+
"furniture",
|
|
9
|
+
"sit"
|
|
10
|
+
],
|
|
11
|
+
"version": "1.1.0",
|
|
12
|
+
"changelog": [
|
|
13
|
+
{
|
|
14
|
+
"version": "1.1.0",
|
|
15
|
+
"notes": "The seat no longer runs on the Multiplayer Server, where it was walking every sit spot's transform chain each frame for nobody to see."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"version": "1.0.1",
|
|
19
|
+
"notes": "Ships the model's texture, which was missing from the folder — without it the model rendered blank white in-world."
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"version": "1.0.0",
|
|
23
|
+
"notes": "Initial release"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"origin": {
|
|
27
|
+
"source": "builtin"
|
|
28
|
+
},
|
|
29
|
+
"requiredPermissions": [
|
|
30
|
+
"ALLOW_TO_MOVE_PLAYER_INSIDE_SCENE",
|
|
31
|
+
"ALLOW_TO_TRIGGER_AVATAR_EMOTE"
|
|
32
|
+
],
|
|
33
|
+
"group": "Seats"
|
|
34
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// Sit on this seat: click a sit spot -> the avatar is placed on it facing forward
|
|
2
|
+
// and a looping sitting emote plays; moving cancels the emote engine-side (the
|
|
3
|
+
// same mechanism the Creator Hub's seat smart items and Genesis Plaza use — no
|
|
4
|
+
// avatar attach). Spots are child entities named "Sit Spot…" carrying only a
|
|
5
|
+
// Transform; this script gives them their collider and pointer event at runtime.
|
|
6
|
+
// With no such children (the standalone Sit Spot prefab), the entity itself is
|
|
7
|
+
// the spot.
|
|
8
|
+
import {
|
|
9
|
+
ColliderLayer,
|
|
10
|
+
InputAction,
|
|
11
|
+
Material,
|
|
12
|
+
MeshCollider,
|
|
13
|
+
MeshRenderer,
|
|
14
|
+
Schemas,
|
|
15
|
+
Transform,
|
|
16
|
+
VisibilityComponent,
|
|
17
|
+
engine,
|
|
18
|
+
pointerEventsSystem,
|
|
19
|
+
type Entity,
|
|
20
|
+
type LastWriteWinElementSetComponentDefinition
|
|
21
|
+
} from '@dcl/sdk/ecs'
|
|
22
|
+
import { Quaternion, Vector3 } from '@dcl/sdk/math'
|
|
23
|
+
import { isServer } from '@dcl/sdk/network'
|
|
24
|
+
import { movePlayerTo, triggerEmote, triggerSceneEmote } from '~system/RestrictedActions'
|
|
25
|
+
|
|
26
|
+
const SPOT_NAME_PREFIX = 'sit spot'
|
|
27
|
+
const HOVER_TEXT = 'Sit Here'
|
|
28
|
+
const MAX_DISTANCE = 6
|
|
29
|
+
const EMOTE_DELAY_S = 0.25
|
|
30
|
+
const SITTING_EMOTES = ['sittingChair1', 'sittingChair2']
|
|
31
|
+
// emote .glb files bundled in this prefab's folder (Genesis Plaza-style custom
|
|
32
|
+
// poses, played via triggerSceneEmote); empty = the predefined chair emotes
|
|
33
|
+
const SCENE_EMOTES: string[] = []
|
|
34
|
+
|
|
35
|
+
// the Plaza-style "you can sit here" hint: a small glowing dot floating over
|
|
36
|
+
// each free spot, pulsing gently, shown only to nearby players
|
|
37
|
+
const DOT_VISIBLE_DIST = 10
|
|
38
|
+
const DOT_OCCUPIED_DIST = 0.9
|
|
39
|
+
const DOT_HEIGHT = 0.55
|
|
40
|
+
const DOT_SIZE = 0.09
|
|
41
|
+
const DOT_PULSE = 0.25
|
|
42
|
+
|
|
43
|
+
type NameValue = { value: string }
|
|
44
|
+
type NameComponent = LastWriteWinElementSetComponentDefinition<NameValue>
|
|
45
|
+
|
|
46
|
+
// Every placed seat prefab bundles its own copy of this script (prefab folders are
|
|
47
|
+
// self-contained), so the component may already be defined by a sibling copy.
|
|
48
|
+
function nameComponent(): NameComponent {
|
|
49
|
+
const existing = engine.getComponentOrNull('core-schema::Name')
|
|
50
|
+
if (existing !== null) return existing as NameComponent
|
|
51
|
+
return engine.defineComponent('core-schema::Name', { value: Schemas.String })
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function isSpotName(name: unknown): boolean {
|
|
55
|
+
return typeof name === 'string' && name.toLowerCase().startsWith(SPOT_NAME_PREFIX)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function sceneRelativeTransform(entity: Entity): { position: Vector3; rotation: Quaternion } {
|
|
59
|
+
const chain: Entity[] = []
|
|
60
|
+
let cursor = entity
|
|
61
|
+
while (cursor !== engine.RootEntity && chain.length < 32) {
|
|
62
|
+
chain.push(cursor)
|
|
63
|
+
const t = Transform.getOrNull(cursor)
|
|
64
|
+
if (t === null) break
|
|
65
|
+
cursor = t.parent ?? engine.RootEntity
|
|
66
|
+
}
|
|
67
|
+
let position = Vector3.Zero()
|
|
68
|
+
let rotation = Quaternion.Identity()
|
|
69
|
+
let scale = Vector3.One()
|
|
70
|
+
for (const link of chain.reverse()) {
|
|
71
|
+
const t = Transform.getOrNull(link)
|
|
72
|
+
if (t === null) continue
|
|
73
|
+
const local = Vector3.create(
|
|
74
|
+
t.position.x * scale.x,
|
|
75
|
+
t.position.y * scale.y,
|
|
76
|
+
t.position.z * scale.z
|
|
77
|
+
)
|
|
78
|
+
position = Vector3.add(position, Vector3.rotate(local, rotation))
|
|
79
|
+
rotation = Quaternion.multiply(rotation, t.rotation)
|
|
80
|
+
scale = Vector3.create(scale.x * t.scale.x, scale.y * t.scale.y, scale.z * t.scale.z)
|
|
81
|
+
}
|
|
82
|
+
return { position, rotation }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export class Seat {
|
|
86
|
+
private emoteIn = 0
|
|
87
|
+
private time = 0
|
|
88
|
+
private dots: Array<{ spot: Entity; dot: Entity; visible: boolean }> = []
|
|
89
|
+
|
|
90
|
+
constructor(
|
|
91
|
+
public src: string,
|
|
92
|
+
public entity: Entity
|
|
93
|
+
) {}
|
|
94
|
+
|
|
95
|
+
start(): void {
|
|
96
|
+
if (isServer()) { return }
|
|
97
|
+
const Name = nameComponent()
|
|
98
|
+
const spots: Entity[] = []
|
|
99
|
+
for (const [child, transform] of engine.getEntitiesWith(Transform)) {
|
|
100
|
+
if (transform.parent !== this.entity) continue
|
|
101
|
+
const name = Name.getOrNull(child)
|
|
102
|
+
if (name !== null && isSpotName(name.value)) spots.push(child)
|
|
103
|
+
}
|
|
104
|
+
if (spots.length === 0) spots.push(this.entity)
|
|
105
|
+
|
|
106
|
+
for (const spot of spots) {
|
|
107
|
+
MeshCollider.setBox(spot, ColliderLayer.CL_POINTER)
|
|
108
|
+
pointerEventsSystem.onPointerDown(
|
|
109
|
+
{
|
|
110
|
+
entity: spot,
|
|
111
|
+
opts: { button: InputAction.IA_POINTER, hoverText: HOVER_TEXT, maxDistance: MAX_DISTANCE }
|
|
112
|
+
},
|
|
113
|
+
() => this.sit(spot)
|
|
114
|
+
)
|
|
115
|
+
// no collider on the dot: clicks pass through to the spot beneath it
|
|
116
|
+
const dot = engine.addEntity()
|
|
117
|
+
Transform.create(dot, {
|
|
118
|
+
parent: spot,
|
|
119
|
+
position: Vector3.create(0, DOT_HEIGHT, 0),
|
|
120
|
+
scale: Vector3.create(DOT_SIZE, DOT_SIZE, DOT_SIZE)
|
|
121
|
+
})
|
|
122
|
+
MeshRenderer.setSphere(dot)
|
|
123
|
+
Material.setPbrMaterial(dot, {
|
|
124
|
+
albedoColor: { r: 1, g: 1, b: 1, a: 0.85 },
|
|
125
|
+
emissiveColor: { r: 1, g: 1, b: 1 },
|
|
126
|
+
emissiveIntensity: 2,
|
|
127
|
+
roughness: 1
|
|
128
|
+
})
|
|
129
|
+
VisibilityComponent.create(dot, { visible: false })
|
|
130
|
+
this.dots.push({ spot, dot, visible: false })
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
update(dt: number): void {
|
|
135
|
+
// The hint walks a transform chain per spot per frame, and a seat is placed
|
|
136
|
+
// by the dozen: without this the Multiplayer Server pays for every one.
|
|
137
|
+
if (isServer()) { return }
|
|
138
|
+
this.time += dt
|
|
139
|
+
this.updateDots()
|
|
140
|
+
if (this.emoteIn <= 0) return
|
|
141
|
+
this.emoteIn -= dt
|
|
142
|
+
if (this.emoteIn > 0) return
|
|
143
|
+
if (SCENE_EMOTES.length > 0) {
|
|
144
|
+
// src is the script's directory (custom/<slug>/scripts) — the emotes live
|
|
145
|
+
// one level up, in the placed prefab's own folder
|
|
146
|
+
const root = this.src.replace(/\/scripts\/?$/, '')
|
|
147
|
+
const emote = SCENE_EMOTES[Math.floor(Math.random() * SCENE_EMOTES.length)]
|
|
148
|
+
void triggerSceneEmote({ src: `${root}/${emote}`, loop: true })
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
const emote = SITTING_EMOTES[Math.floor(Math.random() * SITTING_EMOTES.length)]
|
|
152
|
+
void triggerEmote({ predefinedEmote: emote })
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private updateDots(): void {
|
|
156
|
+
const player = Transform.getOrNull(engine.PlayerEntity)?.position
|
|
157
|
+
const pulse = 1 + DOT_PULSE * Math.sin(this.time * 3)
|
|
158
|
+
for (const entry of this.dots) {
|
|
159
|
+
let visible = false
|
|
160
|
+
if (player !== undefined) {
|
|
161
|
+
const world = sceneRelativeTransform(entry.spot).position
|
|
162
|
+
const dist = Vector3.distance(player, world)
|
|
163
|
+
// hidden while someone (you) is on the spot — a glow over a seated
|
|
164
|
+
// avatar's head reads as a bug, not a hint
|
|
165
|
+
visible = dist < DOT_VISIBLE_DIST && dist > DOT_OCCUPIED_DIST
|
|
166
|
+
}
|
|
167
|
+
if (entry.visible !== visible) {
|
|
168
|
+
entry.visible = visible
|
|
169
|
+
VisibilityComponent.getMutable(entry.dot).visible = visible
|
|
170
|
+
}
|
|
171
|
+
if (visible) {
|
|
172
|
+
Transform.getMutable(entry.dot).scale = Vector3.create(
|
|
173
|
+
DOT_SIZE * pulse,
|
|
174
|
+
DOT_SIZE * pulse,
|
|
175
|
+
DOT_SIZE * pulse
|
|
176
|
+
)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private sit(spot: Entity): void {
|
|
182
|
+
const world = sceneRelativeTransform(spot)
|
|
183
|
+
const forward = Vector3.rotate(Vector3.Forward(), world.rotation)
|
|
184
|
+
void movePlayerTo({
|
|
185
|
+
newRelativePosition: world.position,
|
|
186
|
+
avatarTarget: Vector3.add(world.position, forward)
|
|
187
|
+
})
|
|
188
|
+
// let the teleport settle before the emote starts, or the walk cancels it
|
|
189
|
+
this.emoteIn = EMOTE_DELAY_S
|
|
190
|
+
}
|
|
191
|
+
}
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"components": [
|
|
4
|
+
{
|
|
5
|
+
"name": "core::GltfContainer",
|
|
6
|
+
"data": {
|
|
7
|
+
"0": {
|
|
8
|
+
"json": {
|
|
9
|
+
"src": "{assetPath}/ModernSofa.glb",
|
|
10
|
+
"visibleMeshesCollisionMask": 0,
|
|
11
|
+
"invisibleMeshesCollisionMask": 3
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "core-schema::Name",
|
|
18
|
+
"data": {
|
|
19
|
+
"0": {
|
|
20
|
+
"json": {
|
|
21
|
+
"value": "Modern Sofa"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"513": {
|
|
25
|
+
"json": {
|
|
26
|
+
"value": "Sit Spot 1"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"514": {
|
|
30
|
+
"json": {
|
|
31
|
+
"value": "Sit Spot 2"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "core::Transform",
|
|
38
|
+
"data": {
|
|
39
|
+
"513": {
|
|
40
|
+
"json": {
|
|
41
|
+
"position": {
|
|
42
|
+
"x": -1.0235,
|
|
43
|
+
"y": 0.1354,
|
|
44
|
+
"z": 0.0251
|
|
45
|
+
},
|
|
46
|
+
"rotation": {
|
|
47
|
+
"x": 0,
|
|
48
|
+
"y": 0.07845906168222427,
|
|
49
|
+
"z": 0,
|
|
50
|
+
"w": 0.9969173669815063
|
|
51
|
+
},
|
|
52
|
+
"scale": {
|
|
53
|
+
"x": 1,
|
|
54
|
+
"y": 1,
|
|
55
|
+
"z": 1
|
|
56
|
+
},
|
|
57
|
+
"parent": 0
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"514": {
|
|
61
|
+
"json": {
|
|
62
|
+
"position": {
|
|
63
|
+
"x": -2.7763,
|
|
64
|
+
"y": 0.1354,
|
|
65
|
+
"z": 0.0293
|
|
66
|
+
},
|
|
67
|
+
"rotation": {
|
|
68
|
+
"x": 0,
|
|
69
|
+
"y": 0.07845907658338547,
|
|
70
|
+
"z": 0,
|
|
71
|
+
"w": 0.9969173669815063
|
|
72
|
+
},
|
|
73
|
+
"scale": {
|
|
74
|
+
"x": 1,
|
|
75
|
+
"y": 1,
|
|
76
|
+
"z": 1
|
|
77
|
+
},
|
|
78
|
+
"parent": 0
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"name": "asset-packs::Script",
|
|
85
|
+
"data": {
|
|
86
|
+
"0": {
|
|
87
|
+
"json": {
|
|
88
|
+
"value": [
|
|
89
|
+
{
|
|
90
|
+
"path": "{assetPath}/scripts/seat.ts",
|
|
91
|
+
"priority": 0,
|
|
92
|
+
"layout": "{\"params\":{},\"actions\":[]}"
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "14706421-460b-4161-b06c-8ce7db73ad11",
|
|
3
|
+
"name": "Modern Sofa",
|
|
4
|
+
"description": "A low modern sofa, seating three. Players can sit along it.",
|
|
5
|
+
"category": "custom",
|
|
6
|
+
"tags": [
|
|
7
|
+
"seat",
|
|
8
|
+
"furniture",
|
|
9
|
+
"sit"
|
|
10
|
+
],
|
|
11
|
+
"version": "1.1.0",
|
|
12
|
+
"changelog": [
|
|
13
|
+
{
|
|
14
|
+
"version": "1.1.0",
|
|
15
|
+
"notes": "The seat no longer runs on the Multiplayer Server, where it was walking every sit spot's transform chain each frame for nobody to see."
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"version": "1.0.0",
|
|
19
|
+
"notes": "Initial release"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"origin": {
|
|
23
|
+
"source": "builtin"
|
|
24
|
+
},
|
|
25
|
+
"requiredPermissions": [
|
|
26
|
+
"ALLOW_TO_MOVE_PLAYER_INSIDE_SCENE",
|
|
27
|
+
"ALLOW_TO_TRIGGER_AVATAR_EMOTE"
|
|
28
|
+
],
|
|
29
|
+
"group": "Seats"
|
|
30
|
+
}
|