@darkclaw921/umgt 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +161 -2
- package/architecture.md +105 -0
- package/bin/lm-game-hub.js +7 -0
- package/dist/server/activity.d.ts +17 -0
- package/dist/server/activity.js +55 -0
- package/dist/server/activity.js.map +1 -0
- package/dist/server/agents/activity.d.ts +36 -0
- package/dist/server/agents/activity.js +117 -0
- package/dist/server/agents/activity.js.map +1 -0
- package/dist/server/agents/claude.d.ts +5 -0
- package/dist/server/agents/claude.js +107 -0
- package/dist/server/agents/claude.js.map +1 -0
- package/dist/server/agents/codex.d.ts +5 -0
- package/dist/server/agents/codex.js +128 -0
- package/dist/server/agents/codex.js.map +1 -0
- package/dist/server/agents/core-tools.d.ts +23 -0
- package/dist/server/agents/core-tools.js +298 -0
- package/dist/server/agents/core-tools.js.map +1 -0
- package/dist/server/agents/core.d.ts +9 -0
- package/dist/server/agents/core.js +106 -0
- package/dist/server/agents/core.js.map +1 -0
- package/dist/server/agents/index.d.ts +5 -0
- package/dist/server/agents/index.js +41 -0
- package/dist/server/agents/index.js.map +1 -0
- package/dist/server/agents/kimi.d.ts +5 -0
- package/dist/server/agents/kimi.js +123 -0
- package/dist/server/agents/kimi.js.map +1 -0
- package/dist/server/agents/rpc.d.ts +19 -0
- package/dist/server/agents/rpc.js +102 -0
- package/dist/server/agents/rpc.js.map +1 -0
- package/dist/server/agents/types.d.ts +51 -0
- package/dist/server/agents/types.js +7 -0
- package/dist/server/agents/types.js.map +1 -0
- package/dist/server/app.d.ts +21 -0
- package/dist/server/app.js +38 -0
- package/dist/server/app.js.map +1 -0
- package/dist/server/asset-catalog.d.ts +5 -0
- package/dist/server/asset-catalog.js +525 -0
- package/dist/server/asset-catalog.js.map +1 -0
- package/dist/server/asset-media.d.ts +16 -0
- package/dist/server/asset-media.js +170 -0
- package/dist/server/asset-media.js.map +1 -0
- package/dist/server/asset-selection.d.ts +71 -0
- package/dist/server/asset-selection.js +273 -0
- package/dist/server/asset-selection.js.map +1 -0
- package/dist/server/assets.d.ts +69 -0
- package/dist/server/assets.js +669 -0
- package/dist/server/assets.js.map +1 -0
- package/dist/server/browser-gateway.d.ts +82 -0
- package/dist/server/browser-gateway.js +285 -0
- package/dist/server/browser-gateway.js.map +1 -0
- package/dist/server/chat-computer.d.ts +13 -0
- package/dist/server/chat-computer.js +29 -0
- package/dist/server/chat-computer.js.map +1 -0
- package/dist/server/chat-games.d.ts +38 -0
- package/dist/server/chat-games.js +202 -0
- package/dist/server/chat-games.js.map +1 -0
- package/dist/server/chat.d.ts +42 -0
- package/dist/server/chat.js +318 -0
- package/dist/server/chat.js.map +1 -0
- package/dist/server/cli.d.ts +14 -0
- package/dist/server/cli.js +117 -0
- package/dist/server/cli.js.map +1 -0
- package/dist/server/core-client.d.ts +69 -0
- package/dist/server/core-client.js +357 -0
- package/dist/server/core-client.js.map +1 -0
- package/dist/server/directory-picker.d.ts +14 -0
- package/dist/server/directory-picker.js +113 -0
- package/dist/server/directory-picker.js.map +1 -0
- package/dist/server/engine.d.ts +36 -0
- package/dist/server/engine.js +507 -0
- package/dist/server/engine.js.map +1 -0
- package/dist/server/events.d.ts +12 -0
- package/dist/server/events.js +137 -0
- package/dist/server/events.js.map +1 -0
- package/dist/server/game-launch.d.ts +16 -0
- package/dist/server/game-launch.js +143 -0
- package/dist/server/game-launch.js.map +1 -0
- package/dist/server/html5.d.ts +9 -0
- package/dist/server/html5.js +107 -0
- package/dist/server/html5.js.map +1 -0
- package/dist/server/interview.d.ts +241 -0
- package/dist/server/interview.js +190 -0
- package/dist/server/interview.js.map +1 -0
- package/dist/server/mcp.d.ts +27 -0
- package/dist/server/mcp.js +91 -0
- package/dist/server/mcp.js.map +1 -0
- package/dist/server/plugins.d.ts +8 -0
- package/dist/server/plugins.js +144 -0
- package/dist/server/plugins.js.map +1 -0
- package/dist/server/process.d.ts +15 -0
- package/dist/server/process.js +89 -0
- package/dist/server/process.js.map +1 -0
- package/dist/server/publication-materials.d.ts +18 -0
- package/dist/server/publication-materials.js +104 -0
- package/dist/server/publication-materials.js.map +1 -0
- package/dist/server/publication-mcp.d.ts +3 -0
- package/dist/server/publication-mcp.js +43 -0
- package/dist/server/publication-mcp.js.map +1 -0
- package/dist/server/publication.d.ts +54 -0
- package/dist/server/publication.js +334 -0
- package/dist/server/publication.js.map +1 -0
- package/dist/server/push.d.ts +81 -0
- package/dist/server/push.js +122 -0
- package/dist/server/push.js.map +1 -0
- package/dist/server/reports.d.ts +4 -0
- package/dist/server/reports.js +40 -0
- package/dist/server/reports.js.map +1 -0
- package/dist/server/roblox-assets.d.ts +41 -0
- package/dist/server/roblox-assets.js +131 -0
- package/dist/server/roblox-assets.js.map +1 -0
- package/dist/server/roblox-connection.d.ts +54 -0
- package/dist/server/roblox-connection.js +331 -0
- package/dist/server/roblox-connection.js.map +1 -0
- package/dist/server/roblox-install.d.ts +4 -0
- package/dist/server/roblox-install.js +170 -0
- package/dist/server/roblox-install.js.map +1 -0
- package/dist/server/roblox-mcp.d.ts +2 -0
- package/dist/server/roblox-mcp.js +34 -0
- package/dist/server/roblox-mcp.js.map +1 -0
- package/dist/server/roblox-play.d.ts +23 -0
- package/dist/server/roblox-play.js +84 -0
- package/dist/server/roblox-play.js.map +1 -0
- package/dist/server/roblox-project-tools.d.ts +11 -0
- package/dist/server/roblox-project-tools.js +119 -0
- package/dist/server/roblox-project-tools.js.map +1 -0
- package/dist/server/roblox-setup.d.ts +37 -0
- package/dist/server/roblox-setup.js +206 -0
- package/dist/server/roblox-setup.js.map +1 -0
- package/dist/server/roblox-skills.d.ts +15 -0
- package/dist/server/roblox-skills.js +15 -0
- package/dist/server/roblox-skills.js.map +1 -0
- package/dist/server/roblox.d.ts +30 -0
- package/dist/server/roblox.js +248 -0
- package/dist/server/roblox.js.map +1 -0
- package/dist/server/routes.d.ts +11 -0
- package/dist/server/routes.js +223 -0
- package/dist/server/routes.js.map +1 -0
- package/dist/server/security.d.ts +4 -0
- package/dist/server/security.js +64 -0
- package/dist/server/security.js.map +1 -0
- package/dist/server/skills.d.ts +4 -0
- package/dist/server/skills.js +123 -0
- package/dist/server/skills.js.map +1 -0
- package/dist/server/store.d.ts +25 -0
- package/dist/server/store.js +89 -0
- package/dist/server/store.js.map +1 -0
- package/dist/server/templates/roblox-coin-run.d.ts +2 -0
- package/dist/server/templates/roblox-coin-run.js +326 -0
- package/dist/server/templates/roblox-coin-run.js.map +1 -0
- package/dist/server/templates/roblox-skills.json +55 -0
- package/dist/server/templates/yandex-sdk.d.ts +3 -0
- package/dist/server/templates/yandex-sdk.js +177 -0
- package/dist/server/templates/yandex-sdk.js.map +1 -0
- package/dist/server/updates.d.ts +28 -0
- package/dist/server/updates.js +99 -0
- package/dist/server/updates.js.map +1 -0
- package/dist/server/video-media.d.ts +47 -0
- package/dist/server/video-media.js +224 -0
- package/dist/server/video-media.js.map +1 -0
- package/dist/server/video-routes.d.ts +7 -0
- package/dist/server/video-routes.js +91 -0
- package/dist/server/video-routes.js.map +1 -0
- package/dist/server/video.d.ts +214 -0
- package/dist/server/video.js +301 -0
- package/dist/server/video.js.map +1 -0
- package/dist/server/web-build.d.ts +16 -0
- package/dist/server/web-build.js +232 -0
- package/dist/server/web-build.js.map +1 -0
- package/dist/server/workflow.d.ts +221 -0
- package/dist/server/workflow.js +826 -0
- package/dist/server/workflow.js.map +1 -0
- package/dist/server/yandex-config.d.ts +33 -0
- package/dist/server/yandex-config.js +12 -0
- package/dist/server/yandex-config.js.map +1 -0
- package/dist/server/yandex-godot.d.ts +5 -0
- package/dist/server/yandex-godot.js +107 -0
- package/dist/server/yandex-godot.js.map +1 -0
- package/dist/shared/aspects.d.ts +48 -0
- package/dist/shared/aspects.js +22 -0
- package/dist/shared/aspects.js.map +1 -0
- package/dist/shared/assistant.d.ts +7 -0
- package/dist/shared/assistant.js +36 -0
- package/dist/shared/assistant.js.map +1 -0
- package/dist/shared/chat.d.ts +46 -0
- package/dist/shared/chat.js +2 -0
- package/dist/shared/chat.js.map +1 -0
- package/dist/shared/settings.d.ts +11 -0
- package/dist/shared/settings.js +25 -0
- package/dist/shared/settings.js.map +1 -0
- package/dist/shared/types.d.ts +510 -0
- package/dist/shared/types.js +2 -0
- package/dist/shared/types.js.map +1 -0
- package/dist/web/apple-touch-icon.png +0 -0
- package/dist/web/assets/AgentActivity-sYJeY5Yf.js +9 -0
- package/dist/web/assets/ArrowRight.es-9w41WqD8.js +1 -0
- package/dist/web/assets/ArrowUpRight.es-BmIrpjWN.js +1 -0
- package/dist/web/assets/AssetMediaPreview-D2cd6oQO.js +1 -0
- package/dist/web/assets/AssetSelectionWizard-a43_6NO7.js +1 -0
- package/dist/web/assets/CaretDown.es-Cq33NYip.js +1 -0
- package/dist/web/assets/CheckCircle.es-D5B3hdvz.js +1 -0
- package/dist/web/assets/CoreAccount-D4ZC8CWv.js +1 -0
- package/dist/web/assets/DownloadSimple.es-DwOWFbs2.js +1 -0
- package/dist/web/assets/FileText.es-D83IIiOG.js +1 -0
- package/dist/web/assets/ImageSquare.es-DxCFt99_.js +1 -0
- package/dist/web/assets/KidsApp-BXWaALoK.css +1 -0
- package/dist/web/assets/KidsApp-D-8t3HPy.js +2 -0
- package/dist/web/assets/MagnifyingGlass.es-rkdOU2rH.js +1 -0
- package/dist/web/assets/PaperPlaneRight.es-U0twumpP.js +1 -0
- package/dist/web/assets/PencilSimple.es-JVHwRvGx.js +1 -0
- package/dist/web/assets/PlainChat-BC4K_tmj.css +1 -0
- package/dist/web/assets/PlainChat-CMxYwKko.js +1 -0
- package/dist/web/assets/Sparkle.es-CmGpvnNm.js +1 -0
- package/dist/web/assets/Square.es-BjNN9Ypc.js +1 -0
- package/dist/web/assets/UploadSimple.es-DxIuxpCC.js +1 -0
- package/dist/web/assets/WarningCircle.es-D63H8cL9.js +1 -0
- package/dist/web/assets/WorkflowJournal-Did0sRta.js +1 -0
- package/dist/web/assets/YandexConfigFields-DDL22Bfw.js +1 -0
- package/dist/web/assets/YandexGamesView-R64RSJRL.js +2 -0
- package/dist/web/assets/bg-build-DIalyCDw.svg +3 -0
- package/dist/web/assets/bg-idea-DHcE-Dhs.svg +3 -0
- package/dist/web/assets/bg-materials-UDVFaueI.svg +3 -0
- package/dist/web/assets/bg-plan-DpfwIsqJ.svg +3 -0
- package/dist/web/assets/bg-play-CNc1QZFK.svg +3 -0
- package/dist/web/assets/dist-7vx7MTaJ.js +1 -0
- package/dist/web/assets/index-Izzbh11U.css +1 -0
- package/dist/web/assets/index-sNciOZYG.js +13 -0
- package/dist/web/assets/jsx-runtime-CdVFa8IP.js +1 -0
- package/dist/web/assets/manrope-cyrillic-wght-normal-Dvxsihut.woff2 +0 -0
- package/dist/web/assets/manrope-greek-wght-normal-DL7QRZyv.woff2 +0 -0
- package/dist/web/assets/manrope-latin-ext-wght-normal-Ch3YOpNY.woff2 +0 -0
- package/dist/web/assets/manrope-latin-wght-normal-DHIcAJRg.woff2 +0 -0
- package/dist/web/assets/manrope-vietnamese-wght-normal-usUDDRr7.woff2 +0 -0
- package/dist/web/assets/resources-DppXCagL.js +1 -0
- package/dist/web/assets/robot-happy-B6YvlU94.svg +24 -0
- package/dist/web/assets/robot-hello-CCsQgsS-.svg +24 -0
- package/dist/web/assets/robot-listen-Buuz9xII.svg +24 -0
- package/dist/web/assets/robot-sad-CRtiNVWs.svg +24 -0
- package/dist/web/assets/robot-think-CJ5fDBTm.svg +24 -0
- package/dist/web/assets/star-big-CSFDKjws.svg +22 -0
- package/dist/web/assets/star-empty-CC-5vioJ.svg +3 -0
- package/dist/web/assets/star-next-ztuDjOHU.svg +9 -0
- package/dist/web/assets/star-on-l_krO3aV.svg +10 -0
- package/dist/web/assets/ui-wHE_yBK0.js +41 -0
- package/dist/web/assets/umgt-logo-DAOkTN9u.png +0 -0
- package/dist/web/assets/unbounded-cyrillic-wght-normal-C627f1f8.woff2 +0 -0
- package/dist/web/assets/unbounded-latin-ext-wght-normal-D6H-S6MW.woff2 +0 -0
- package/dist/web/assets/unbounded-latin-wght-normal-D5afBTBx.woff2 +0 -0
- package/dist/web/assets/unbounded-vietnamese-wght-normal-rat7GD3o.woff2 +0 -0
- package/dist/web/assets/workflow-BhcU9uvG.css +1 -0
- package/dist/web/assets/workflow-BrIKN5ER.js +34 -0
- package/dist/web/favicon.ico +0 -0
- package/dist/web/icons/favicon-16.png +0 -0
- package/dist/web/icons/favicon-32.png +0 -0
- package/dist/web/icons/icon-192.png +0 -0
- package/dist/web/icons/icon-512.png +0 -0
- package/dist/web/icons/maskable-192.png +0 -0
- package/dist/web/icons/maskable-512.png +0 -0
- package/dist/web/index.html +28 -0
- package/dist/web/manifest.webmanifest +19 -0
- package/dist/web/sw.js +25 -0
- package/docs/agent-activity-ui.md +33 -0
- package/docs/agent-activity.md +43 -0
- package/docs/agent-permissions-ui.md +15 -0
- package/docs/api.md +145 -0
- package/docs/approval-journal.md +13 -0
- package/docs/asset-media.md +27 -0
- package/docs/asset-providers.md +34 -0
- package/docs/asset-selection.md +31 -0
- package/docs/automatic-approvals.md +15 -0
- package/docs/background-game-launch.md +17 -0
- package/docs/billing-validation.md +23 -0
- package/docs/core-isolation.md +37 -0
- package/docs/core.md +45 -0
- package/docs/generated-text-ui.md +41 -0
- package/docs/interactive-interview-ui.md +29 -0
- package/docs/interactive-interview.md +52 -0
- package/docs/local-codex.md +51 -0
- package/docs/local-meshy.md +13 -0
- package/docs/markdown.md +11 -0
- package/docs/permission-ui.md +11 -0
- package/docs/plan.md +47 -0
- package/docs/remote-core-deployment.md +47 -0
- package/docs/roblox.md +90 -0
- package/docs/validation.md +228 -0
- package/docs/video-reference.md +35 -0
- package/docs/workflow-journal-ui.md +21 -0
- package/docs/yandex-foundation.md +27 -0
- package/docs/yandex-games.md +45 -0
- package/package.json +95 -4
- package/scripts/create-roblox-demo.mjs +31 -0
- package/scripts/diagnose-roblox-mcp.mjs +45 -0
- package/scripts/open-hub-chrome.mjs +60 -0
- package/scripts/smoke-agent.mjs +91 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import { mkdirSync, realpathSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, resolve } from 'node:path';
|
|
4
|
+
export class DocumentStore {
|
|
5
|
+
filename;
|
|
6
|
+
db;
|
|
7
|
+
transactionDepth = 0;
|
|
8
|
+
constructor(filename) {
|
|
9
|
+
this.filename = filename;
|
|
10
|
+
if (filename !== ':memory:')
|
|
11
|
+
mkdirSync(dirname(filename), { recursive: true, mode: 0o700 });
|
|
12
|
+
this.db = new DatabaseSync(filename);
|
|
13
|
+
this.db.exec(`PRAGMA journal_mode = WAL; PRAGMA busy_timeout = 5000;
|
|
14
|
+
CREATE TABLE IF NOT EXISTS documents (collection TEXT NOT NULL, id TEXT NOT NULL, data TEXT NOT NULL, PRIMARY KEY(collection, id));
|
|
15
|
+
CREATE TABLE IF NOT EXISTS events (id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT NOT NULL, payload TEXT NOT NULL, project_id TEXT, created_at TEXT NOT NULL);
|
|
16
|
+
CREATE INDEX IF NOT EXISTS events_project ON events(project_id, id);`);
|
|
17
|
+
}
|
|
18
|
+
get(collection, id) {
|
|
19
|
+
const row = this.db.prepare('SELECT data FROM documents WHERE collection = ? AND id = ?').get(collection, id);
|
|
20
|
+
return row ? JSON.parse(String(row.data)) : undefined;
|
|
21
|
+
}
|
|
22
|
+
put(collection, doc) {
|
|
23
|
+
this.db.prepare('INSERT INTO documents(collection, id, data) VALUES (?, ?, ?) ON CONFLICT(collection, id) DO UPDATE SET data = excluded.data').run(collection, doc.id, JSON.stringify(doc));
|
|
24
|
+
return doc;
|
|
25
|
+
}
|
|
26
|
+
list(collection) {
|
|
27
|
+
return this.db.prepare('SELECT data FROM documents WHERE collection = ? ORDER BY rowid').all(collection).map(row => JSON.parse(String(row.data)));
|
|
28
|
+
}
|
|
29
|
+
delete(collection, id) {
|
|
30
|
+
return Number(this.db.prepare('DELETE FROM documents WHERE collection = ? AND id = ?').run(collection, id).changes) > 0;
|
|
31
|
+
}
|
|
32
|
+
transaction(fn) {
|
|
33
|
+
const savepoint = `tx_${this.transactionDepth++}`;
|
|
34
|
+
this.db.exec(`SAVEPOINT ${savepoint}`);
|
|
35
|
+
try {
|
|
36
|
+
const result = fn();
|
|
37
|
+
if (result instanceof Promise)
|
|
38
|
+
throw new Error('DocumentStore.transaction requires a synchronous function');
|
|
39
|
+
this.db.exec(`RELEASE ${savepoint}`);
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
this.db.exec(`ROLLBACK TO ${savepoint}; RELEASE ${savepoint}`);
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
this.transactionDepth--;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
appendEvent(type, payload, projectId) {
|
|
51
|
+
const createdAt = new Date().toISOString();
|
|
52
|
+
const result = this.db.prepare('INSERT INTO events(type,payload,project_id,created_at) VALUES (?,?,?,?)').run(type, JSON.stringify(payload ?? null), projectId ?? null, createdAt);
|
|
53
|
+
return { id: Number(result.lastInsertRowid), type, payload, projectId, createdAt };
|
|
54
|
+
}
|
|
55
|
+
eventsAfter(afterId = 0, projectId, limit = 1000) {
|
|
56
|
+
const query = projectId
|
|
57
|
+
? this.db.prepare('SELECT * FROM events WHERE id > ? AND project_id = ? ORDER BY id LIMIT ?').all(afterId, projectId, limit)
|
|
58
|
+
: this.db.prepare('SELECT * FROM events WHERE id > ? ORDER BY id LIMIT ?').all(afterId, limit);
|
|
59
|
+
return query.map(row => ({ id: Number(row.id), type: String(row.type), payload: JSON.parse(String(row.payload)), projectId: row.project_id === null ? undefined : String(row.project_id), createdAt: String(row.created_at) }));
|
|
60
|
+
}
|
|
61
|
+
close() { this.db.close(); }
|
|
62
|
+
}
|
|
63
|
+
export class Store extends DocumentStore {
|
|
64
|
+
dataDir;
|
|
65
|
+
projectStores = new Map();
|
|
66
|
+
constructor(dataDir) {
|
|
67
|
+
super(join(resolve(dataDir), 'hub.sqlite'));
|
|
68
|
+
this.dataDir = dataDir;
|
|
69
|
+
}
|
|
70
|
+
project(projectId) {
|
|
71
|
+
const project = this.get('projects', projectId);
|
|
72
|
+
if (!project)
|
|
73
|
+
throw Object.assign(new Error('Project not found'), { statusCode: 404 });
|
|
74
|
+
const path = realpathSync(project.path);
|
|
75
|
+
let store = this.projectStores.get(path);
|
|
76
|
+
if (!store) {
|
|
77
|
+
store = new DocumentStore(join(path, '.lm-game-hub', 'state.sqlite'));
|
|
78
|
+
this.projectStores.set(path, store);
|
|
79
|
+
}
|
|
80
|
+
return store;
|
|
81
|
+
}
|
|
82
|
+
close() {
|
|
83
|
+
for (const store of this.projectStores.values())
|
|
84
|
+
store.close();
|
|
85
|
+
this.projectStores.clear();
|
|
86
|
+
super.close();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/server/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
export const coinRunServer = String.raw `--!strict
|
|
2
|
+
local Players = game:GetService("Players")
|
|
3
|
+
local Workspace = game:GetService("Workspace")
|
|
4
|
+
local Lighting = game:GetService("Lighting")
|
|
5
|
+
Lighting.ClockTime = 14
|
|
6
|
+
Lighting.Brightness = 2
|
|
7
|
+
Lighting.Ambient = Color3.fromRGB(130, 150, 180)
|
|
8
|
+
-- FallenPartsDestroyHeight is a restricted engine property; keep its place default.
|
|
9
|
+
|
|
10
|
+
local world = Instance.new("Folder")
|
|
11
|
+
world.Name = "CoinRun"
|
|
12
|
+
world.Parent = Workspace
|
|
13
|
+
local function part(name: string, size: Vector3, position: Vector3, color: Color3): Part
|
|
14
|
+
local p = Instance.new("Part")
|
|
15
|
+
p.Name, p.Size, p.Position, p.Color = name, size, position, color
|
|
16
|
+
p.Anchored = true
|
|
17
|
+
p.TopSurface = Enum.SurfaceType.Smooth
|
|
18
|
+
p.BottomSurface = Enum.SurfaceType.Smooth
|
|
19
|
+
p.Parent = world
|
|
20
|
+
return p
|
|
21
|
+
end
|
|
22
|
+
local function sign(p: BasePart, text: string)
|
|
23
|
+
local gui = Instance.new("BillboardGui")
|
|
24
|
+
gui.Size = UDim2.fromOffset(360, 70)
|
|
25
|
+
gui.StudsOffset = Vector3.new(0, 5, 0)
|
|
26
|
+
gui.AlwaysOnTop = true
|
|
27
|
+
gui.Parent = p
|
|
28
|
+
local label = Instance.new("TextLabel")
|
|
29
|
+
label.Size = UDim2.fromScale(1, 1)
|
|
30
|
+
label.BackgroundTransparency = 1
|
|
31
|
+
label.Text, label.TextColor3 = text, Color3.new(1, 1, 1)
|
|
32
|
+
label.TextStrokeTransparency = 0.4
|
|
33
|
+
label.TextScaled = true
|
|
34
|
+
label.Font = Enum.Font.GothamBold
|
|
35
|
+
label.Parent = gui
|
|
36
|
+
end
|
|
37
|
+
local gold = Color3.fromRGB(255, 207, 55)
|
|
38
|
+
local green = Color3.fromRGB(81, 179, 119)
|
|
39
|
+
local blue = Color3.fromRGB(72, 152, 225)
|
|
40
|
+
local gate = part("Start", Vector3.new(14, 1, 10), Vector3.new(0, 0.6, 0), blue)
|
|
41
|
+
sign(gate, "COIN RUN / RUN · JUMP · COLLECT")
|
|
42
|
+
|
|
43
|
+
-- A gentle staircase, stepping islands and low hurdles make the jumps useful.
|
|
44
|
+
local platforms: {Part} = {}
|
|
45
|
+
for i = 1, 5 do
|
|
46
|
+
local p = part("Step" .. i, Vector3.new(12, 1, 7), Vector3.new(-20, i * 2, -18 - i * 8), blue)
|
|
47
|
+
table.insert(platforms, p)
|
|
48
|
+
end
|
|
49
|
+
for i = 1, 5 do
|
|
50
|
+
local p = part("Island" .. i, Vector3.new(8, 1, 8), Vector3.new(17 + (i % 2) * 5, 3 + (i % 2) * 2, -65 - i * 12), green)
|
|
51
|
+
table.insert(platforms, p)
|
|
52
|
+
end
|
|
53
|
+
for i = 1, 4 do
|
|
54
|
+
part("Hurdle" .. i, Vector3.new(12, 2.5, 2), Vector3.new(0, 1.25, -25 - i * 25), blue)
|
|
55
|
+
end
|
|
56
|
+
-- Creator Store assets selected and imported through Game Hub.
|
|
57
|
+
local assetFolder = game:GetService("ReplicatedStorage"):FindFirstChild("LMHubAssets")
|
|
58
|
+
local function decoration(assetId: string, name: string, position: Vector3, height: number, yaw: number): boolean
|
|
59
|
+
local template = assetFolder and assetFolder:FindFirstChild("Asset" .. assetId)
|
|
60
|
+
if not template or not template:IsA("Model") then return false end
|
|
61
|
+
local model = template:Clone()
|
|
62
|
+
model.Name = name
|
|
63
|
+
local _, initialSize = model:GetBoundingBox()
|
|
64
|
+
if initialSize.Y <= 0 then model:Destroy(); return false end
|
|
65
|
+
model:ScaleTo(height / initialSize.Y)
|
|
66
|
+
local box, size = model:GetBoundingBox()
|
|
67
|
+
local offset = model:GetPivot():ToObjectSpace(box)
|
|
68
|
+
model:PivotTo(CFrame.new(position + Vector3.new(0, size.Y / 2, 0)) * CFrame.Angles(0, yaw, 0) * offset:Inverse())
|
|
69
|
+
for _, item in model:GetDescendants() do
|
|
70
|
+
if item:IsA("BasePart") then item.Anchored = true; item.CanCollide = false; item.CanTouch = false end
|
|
71
|
+
end
|
|
72
|
+
model.Parent = world
|
|
73
|
+
return true
|
|
74
|
+
end
|
|
75
|
+
for i = 1, 16 do
|
|
76
|
+
local side = if i % 2 == 0 then 1 else -1
|
|
77
|
+
local pos = Vector3.new(side * (37 + (i % 3) * 5), 0, 8 - i * 11)
|
|
78
|
+
if not decoration("5616880673", "Pine" .. i, pos, 15 + (i % 3) * 2, i * 1.4) then
|
|
79
|
+
part("TreeTrunk" .. i, Vector3.new(2, 8, 2), pos + Vector3.new(0, 4, 0), Color3.fromRGB(105, 77, 52))
|
|
80
|
+
local crown = part("TreeCrown" .. i, Vector3.new(10, 10, 10), pos + Vector3.new(0, 11, 0), green)
|
|
81
|
+
crown.Shape = Enum.PartType.Ball
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
for i = 1, 12 do
|
|
85
|
+
local side = if i % 2 == 0 then 1 else -1
|
|
86
|
+
decoration("7299047040", "Rocks" .. i, Vector3.new(side * (30 + i % 4), 0, -6 - i * 12), 2 + i % 3, i * 0.8)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
local coins = Instance.new("Folder")
|
|
90
|
+
coins.Name = "Coins"
|
|
91
|
+
coins.Parent = world
|
|
92
|
+
local checkpoints: {[Player]: Vector3} = {}
|
|
93
|
+
local claimed: {[Player]: {[number]: boolean}} = {}
|
|
94
|
+
local function characterPlayer(hit: BasePart): Player?
|
|
95
|
+
local model = hit:FindFirstAncestorOfClass("Model")
|
|
96
|
+
return if model then Players:GetPlayerFromCharacter(model) else nil
|
|
97
|
+
end
|
|
98
|
+
local function statFor(player: Player): IntValue?
|
|
99
|
+
local stats = player:FindFirstChild("leaderstats")
|
|
100
|
+
local stat = stats and stats:FindFirstChild("Coins")
|
|
101
|
+
return if stat and stat:IsA("IntValue") then stat else nil
|
|
102
|
+
end
|
|
103
|
+
local TOTAL = 20
|
|
104
|
+
Workspace:SetAttribute("CoinRunTotal", TOTAL)
|
|
105
|
+
for id = 1, TOTAL do
|
|
106
|
+
local pos: Vector3
|
|
107
|
+
if id <= 10 then
|
|
108
|
+
pos = Vector3.new(0, 3, -8 - (id - 1) * 15)
|
|
109
|
+
else
|
|
110
|
+
local p = platforms[id - 10]
|
|
111
|
+
pos = p.Position + Vector3.new(0, 3, 0)
|
|
112
|
+
end
|
|
113
|
+
local coin = part("Coin" .. id, Vector3.new(0.5, 2.5, 2.5), pos, gold)
|
|
114
|
+
coin.Shape = Enum.PartType.Cylinder
|
|
115
|
+
coin.Orientation = Vector3.new(0, 0, 90)
|
|
116
|
+
coin.Material = Enum.Material.Neon
|
|
117
|
+
coin.CanCollide = false
|
|
118
|
+
coin:SetAttribute("CoinId", id)
|
|
119
|
+
coin.Parent = coins
|
|
120
|
+
coin.Touched:Connect(function(hit: BasePart)
|
|
121
|
+
local player = characterPlayer(hit)
|
|
122
|
+
if not player then return end
|
|
123
|
+
local character = player.Character
|
|
124
|
+
local root = character and character:FindFirstChild("HumanoidRootPart")
|
|
125
|
+
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
|
|
126
|
+
local collected = claimed[player]
|
|
127
|
+
local stat = statFor(player)
|
|
128
|
+
if not root or not root:IsA("BasePart") or not humanoid or humanoid.Health <= 0 or not collected or not stat then return end
|
|
129
|
+
if collected[id] or (root.Position - coin.Position).Magnitude > 7 then return end
|
|
130
|
+
-- No yields between validation and update: multiple limb touches grant once.
|
|
131
|
+
collected[id] = true
|
|
132
|
+
stat.Value += 1
|
|
133
|
+
player:SetAttribute("CoinRunCollected" .. id, true)
|
|
134
|
+
print("COIN_RUN: " .. player.Name .. " coins=" .. stat.Value)
|
|
135
|
+
end)
|
|
136
|
+
end
|
|
137
|
+
local checkpoint = part("Checkpoint", Vector3.new(14, 0.5, 8), Vector3.new(0, 0.4, -78), green)
|
|
138
|
+
sign(checkpoint, "CHECKPOINT")
|
|
139
|
+
checkpoint.Touched:Connect(function(hit: BasePart)
|
|
140
|
+
local player = characterPlayer(hit)
|
|
141
|
+
if player then
|
|
142
|
+
checkpoints[player] = checkpoint.Position + Vector3.new(0, 5, 0)
|
|
143
|
+
player:SetAttribute("CoinRunCheckpoint", true)
|
|
144
|
+
end
|
|
145
|
+
end)
|
|
146
|
+
local finish = part("Finish", Vector3.new(20, 1, 12), Vector3.new(0, 0.7, -162), gold)
|
|
147
|
+
sign(finish, "FINISH / COLLECT ALL 20 COINS")
|
|
148
|
+
finish.Touched:Connect(function(hit: BasePart)
|
|
149
|
+
local player = characterPlayer(hit)
|
|
150
|
+
local stat = player and statFor(player)
|
|
151
|
+
if player and stat and stat.Value == TOTAL and not player:GetAttribute("CoinRunWon") then
|
|
152
|
+
player:SetAttribute("CoinRunWon", true)
|
|
153
|
+
print("COIN_RUN_WIN: " .. player.Name)
|
|
154
|
+
end
|
|
155
|
+
end)
|
|
156
|
+
local function added(player: Player)
|
|
157
|
+
claimed[player] = {}
|
|
158
|
+
local stats = Instance.new("Folder")
|
|
159
|
+
stats.Name, stats.Parent = "leaderstats", player
|
|
160
|
+
local stat = Instance.new("IntValue")
|
|
161
|
+
stat.Name, stat.Parent = "Coins", stats
|
|
162
|
+
local function spawned(character: Model)
|
|
163
|
+
local humanoid = character:WaitForChild("Humanoid") :: Humanoid
|
|
164
|
+
humanoid.WalkSpeed = 22
|
|
165
|
+
humanoid.UseJumpPower = true
|
|
166
|
+
humanoid.JumpPower = 55
|
|
167
|
+
local root = character:WaitForChild("HumanoidRootPart") :: BasePart
|
|
168
|
+
local checkpointPosition = checkpoints[player]
|
|
169
|
+
if checkpointPosition then character:PivotTo(CFrame.new(checkpointPosition)) end
|
|
170
|
+
end
|
|
171
|
+
player.CharacterAdded:Connect(spawned)
|
|
172
|
+
if player.Character then task.spawn(spawned, player.Character) end
|
|
173
|
+
end
|
|
174
|
+
Players.PlayerAdded:Connect(added)
|
|
175
|
+
for _, player in Players:GetPlayers() do added(player) end
|
|
176
|
+
Players.PlayerRemoving:Connect(function(player: Player)
|
|
177
|
+
claimed[player], checkpoints[player] = nil, nil
|
|
178
|
+
end)
|
|
179
|
+
print("COIN_RUN_READY: 20 coins, 10 jumping platforms, checkpoint and finish")
|
|
180
|
+
`;
|
|
181
|
+
export const coinRunClient = String.raw `--!strict
|
|
182
|
+
local Players = game:GetService("Players")
|
|
183
|
+
local RunService = game:GetService("RunService")
|
|
184
|
+
local player = Players.LocalPlayer
|
|
185
|
+
local gui = Instance.new("ScreenGui")
|
|
186
|
+
gui.Name = "CoinRunHUD"
|
|
187
|
+
gui.ResetOnSpawn = false
|
|
188
|
+
gui.Parent = player:WaitForChild("PlayerGui")
|
|
189
|
+
local panel = Instance.new("Frame")
|
|
190
|
+
panel.Size = UDim2.new(0.9, 0, 0, 135)
|
|
191
|
+
panel.Position = UDim2.new(0.05, 0, 0, 16)
|
|
192
|
+
panel.BackgroundColor3 = Color3.fromRGB(19, 33, 43)
|
|
193
|
+
panel.BackgroundTransparency = 0.12
|
|
194
|
+
panel.Parent = gui
|
|
195
|
+
local constraint = Instance.new("UISizeConstraint")
|
|
196
|
+
constraint.MaxSize = Vector2.new(600, 135)
|
|
197
|
+
constraint.Parent = panel
|
|
198
|
+
local corner = Instance.new("UICorner")
|
|
199
|
+
corner.CornerRadius = UDim.new(0, 16)
|
|
200
|
+
corner.Parent = panel
|
|
201
|
+
local function label(y: number, height: number, size: number, color: Color3): TextLabel
|
|
202
|
+
local t = Instance.new("TextLabel")
|
|
203
|
+
t.BackgroundTransparency = 1
|
|
204
|
+
t.Size = UDim2.new(1, -32, 0, height)
|
|
205
|
+
t.Position = UDim2.fromOffset(16, y)
|
|
206
|
+
t.Font = Enum.Font.GothamBold
|
|
207
|
+
t.TextSize = size
|
|
208
|
+
t.TextColor3 = color
|
|
209
|
+
t.TextXAlignment = Enum.TextXAlignment.Left
|
|
210
|
+
t.TextWrapped = true
|
|
211
|
+
t.Parent = panel
|
|
212
|
+
return t
|
|
213
|
+
end
|
|
214
|
+
local title = label(10, 28, 24, Color3.fromRGB(255, 210, 64))
|
|
215
|
+
title.Text = "COIN RUN"
|
|
216
|
+
local counter = label(42, 26, 21, Color3.new(1, 1, 1))
|
|
217
|
+
local hint = label(73, 52, 16, Color3.fromRGB(191, 210, 224))
|
|
218
|
+
hint.Text = "WASD / arrows: run · Space: jump\nTouch: joystick + jump button. Collect 20 coins, then reach the finish."
|
|
219
|
+
local stats = player:WaitForChild("leaderstats")
|
|
220
|
+
local coins = stats:WaitForChild("Coins") :: IntValue
|
|
221
|
+
-- Audio IDs and templates come from the Hub's imported Creator Store receipts.
|
|
222
|
+
local SoundService = game:GetService("SoundService")
|
|
223
|
+
local ContentProvider = game:GetService("ContentProvider")
|
|
224
|
+
local assets = game:GetService("ReplicatedStorage"):FindFirstChild("LMHubAssets")
|
|
225
|
+
local audioFolder = Instance.new("Folder")
|
|
226
|
+
audioFolder.Name = "CoinRunAudio"
|
|
227
|
+
audioFolder.Parent = SoundService
|
|
228
|
+
local sfxGroup = Instance.new("SoundGroup")
|
|
229
|
+
sfxGroup.Name = "CoinRunSFX"
|
|
230
|
+
sfxGroup.Volume = 0.65
|
|
231
|
+
sfxGroup.Parent = SoundService
|
|
232
|
+
local musicGroup = Instance.new("SoundGroup")
|
|
233
|
+
musicGroup.Name = "CoinRunMusic"
|
|
234
|
+
musicGroup.Volume = 0.22
|
|
235
|
+
musicGroup.Parent = SoundService
|
|
236
|
+
local function sound(name: string, assetId: string, volume: number, looped: boolean, group: SoundGroup): Sound
|
|
237
|
+
local template = assets and assets:FindFirstChild("Asset" .. assetId)
|
|
238
|
+
local audio = if template and template:IsA("Sound") then template:Clone() else Instance.new("Sound")
|
|
239
|
+
audio.Name = name
|
|
240
|
+
audio.Volume, audio.Looped, audio.SoundGroup = volume, looped, group
|
|
241
|
+
audio.Parent = audioFolder
|
|
242
|
+
return audio
|
|
243
|
+
end
|
|
244
|
+
local pickupSound = sound("Pickup", "113730061669739", 0.7, false, sfxGroup)
|
|
245
|
+
local jumpSound = sound("Jump", "6746569988", 0.25, false, sfxGroup)
|
|
246
|
+
local checkpointSound = sound("Checkpoint", "113730061669739", 0.6, false, sfxGroup)
|
|
247
|
+
checkpointSound.PlaybackSpeed = 0.75
|
|
248
|
+
local winSound = sound("Victory", "1844016113", 0.65, false, sfxGroup)
|
|
249
|
+
local music = sound("Music", "137489151351263", 0.5, true, musicGroup)
|
|
250
|
+
local function play(audio: Sound)
|
|
251
|
+
if audio.SoundId == "" then return end
|
|
252
|
+
audio.TimePosition = 0
|
|
253
|
+
audio:Play()
|
|
254
|
+
end
|
|
255
|
+
local mute = Instance.new("TextButton")
|
|
256
|
+
mute.Name = "MuteAudio"
|
|
257
|
+
mute.Size = UDim2.fromOffset(110, 28)
|
|
258
|
+
mute.Position = UDim2.new(1, -122, 0, 10)
|
|
259
|
+
mute.BackgroundColor3 = Color3.fromRGB(40, 62, 72)
|
|
260
|
+
mute.TextColor3 = Color3.new(1, 1, 1)
|
|
261
|
+
mute.Text = "SOUND: ON"
|
|
262
|
+
mute.Font = Enum.Font.GothamBold
|
|
263
|
+
mute.TextSize = 12
|
|
264
|
+
mute.Parent = panel
|
|
265
|
+
local muted = false
|
|
266
|
+
mute.Activated:Connect(function()
|
|
267
|
+
muted = not muted
|
|
268
|
+
sfxGroup.Volume = if muted then 0 else 0.65
|
|
269
|
+
musicGroup.Volume = if muted then 0 else 0.22
|
|
270
|
+
mute.Text = if muted then "SOUND: OFF" else "SOUND: ON"
|
|
271
|
+
end)
|
|
272
|
+
local function bindJump(character: Model)
|
|
273
|
+
local humanoid = character:WaitForChild("Humanoid") :: Humanoid
|
|
274
|
+
humanoid.StateChanged:Connect(function(_, state)
|
|
275
|
+
if state == Enum.HumanoidStateType.Jumping then play(jumpSound) end
|
|
276
|
+
end)
|
|
277
|
+
end
|
|
278
|
+
player.CharacterAdded:Connect(bindJump)
|
|
279
|
+
if player.Character then task.spawn(bindJump, player.Character) end
|
|
280
|
+
local lastCoins = coins.Value
|
|
281
|
+
coins.Changed:Connect(function()
|
|
282
|
+
if coins.Value > lastCoins then play(pickupSound) end
|
|
283
|
+
lastCoins = coins.Value
|
|
284
|
+
end)
|
|
285
|
+
player:GetAttributeChangedSignal("CoinRunCheckpoint"):Connect(function()
|
|
286
|
+
if player:GetAttribute("CoinRunCheckpoint") then play(checkpointSound) end
|
|
287
|
+
end)
|
|
288
|
+
player:GetAttributeChangedSignal("CoinRunWon"):Connect(function()
|
|
289
|
+
if player:GetAttribute("CoinRunWon") then play(winSound) end
|
|
290
|
+
end)
|
|
291
|
+
task.spawn(function()
|
|
292
|
+
local ok, err = pcall(function() ContentProvider:PreloadAsync(audioFolder:GetChildren()) end)
|
|
293
|
+
if not ok then warn("COIN_RUN_AUDIO: " .. tostring(err)) end
|
|
294
|
+
if music.SoundId ~= "" then music:Play() end
|
|
295
|
+
end)
|
|
296
|
+
local function update()
|
|
297
|
+
counter.Text = "COINS " .. coins.Value .. " / 20"
|
|
298
|
+
if player:GetAttribute("CoinRunWon") then
|
|
299
|
+
title.Text = "YOU DID IT!"
|
|
300
|
+
hint.Text = "All 20 coins collected. Thanks for playing!"
|
|
301
|
+
elseif coins.Value == 20 then
|
|
302
|
+
hint.Text = "All coins collected! Run to the golden finish gate."
|
|
303
|
+
elseif player:GetAttribute("CoinRunCheckpoint") then
|
|
304
|
+
hint.Text = "Checkpoint saved. Keep jumping and collecting!"
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
coins.Changed:Connect(update)
|
|
308
|
+
player:GetAttributeChangedSignal("CoinRunWon"):Connect(update)
|
|
309
|
+
player:GetAttributeChangedSignal("CoinRunCheckpoint"):Connect(update)
|
|
310
|
+
update()
|
|
311
|
+
local folder = workspace:WaitForChild("CoinRun"):WaitForChild("Coins")
|
|
312
|
+
local bases: {[BasePart]: CFrame} = {}
|
|
313
|
+
for _, obj in folder:GetChildren() do
|
|
314
|
+
if obj:IsA("BasePart") then bases[obj] = obj.CFrame end
|
|
315
|
+
end
|
|
316
|
+
local elapsed = 0
|
|
317
|
+
RunService.RenderStepped:Connect(function(delta: number)
|
|
318
|
+
elapsed += delta
|
|
319
|
+
for coin, base in bases do
|
|
320
|
+
local id = coin:GetAttribute("CoinId")
|
|
321
|
+
coin.LocalTransparencyModifier = if player:GetAttribute("CoinRunCollected" .. tostring(id)) then 1 else 0
|
|
322
|
+
coin.CFrame = CFrame.new(base.Position + Vector3.new(0, math.sin(elapsed * 2) * 0.2, 0)) * CFrame.Angles(0, elapsed * 1.5, math.pi / 2)
|
|
323
|
+
end
|
|
324
|
+
end)
|
|
325
|
+
`;
|
|
326
|
+
//# sourceMappingURL=roblox-coin-run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roblox-coin-run.js","sourceRoot":"","sources":["../../../src/server/templates/roblox-coin-run.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmLtC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgJtC,CAAC"}
|