@myvillage/cli 1.64.6 → 1.64.7
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/package.json +2 -1
- package/src/commands/create-game.js +7 -1
- package/src/utils/templates.js +86 -28
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@myvillage/cli",
|
|
3
|
-
"version": "1.64.
|
|
3
|
+
"version": "1.64.7",
|
|
4
4
|
"description": "MyVillageOS CLI for community developers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"open": "^10.0.3",
|
|
40
40
|
"ora": "^8.0.1",
|
|
41
41
|
"p-limit": "^5.0.0",
|
|
42
|
+
"tar": "^7.5.16",
|
|
42
43
|
"update-notifier": "^7.0.0",
|
|
43
44
|
"yaml": "^2.3.0",
|
|
44
45
|
"zod": "^3.22.0"
|
|
@@ -214,9 +214,15 @@ async function createUnityGame(options = {}) {
|
|
|
214
214
|
console.log();
|
|
215
215
|
console.log(brand.green(` \u2713 Unity game "${answers.name}" created!`));
|
|
216
216
|
console.log(brand.teal(` Unity: ${scaffold.unityVersion}`));
|
|
217
|
-
console.log(brand.teal(` GameKit SDK: ${scaffold.sdkVersion}`));
|
|
217
|
+
console.log(brand.teal(` GameKit SDK: ${scaffold.sdkVersion}${scaffold.sdkEmbedded ? ' (bundled — no git needed)' : ''}`));
|
|
218
218
|
console.log(brand.teal(` Orientation: ${orientation} (${orientation === 'landscape' ? 'web only' : 'muni mobile + web'})`));
|
|
219
219
|
console.log();
|
|
220
|
+
if (!scaffold.sdkEmbedded) {
|
|
221
|
+
console.log(chalk.yellow(' ⚠ Could not download the GameKit SDK (offline?). The project falls back to a'));
|
|
222
|
+
console.log(chalk.yellow(' git-URL dependency, so opening it in Unity will require git to be installed.'));
|
|
223
|
+
console.log(chalk.yellow(' Re-run this command with a network connection to bundle the SDK locally instead.'));
|
|
224
|
+
console.log();
|
|
225
|
+
}
|
|
220
226
|
console.log(brand.teal(' Next steps:'));
|
|
221
227
|
console.log();
|
|
222
228
|
console.log(` 1. ${brand.gold('Open this project in Unity Hub')} (Add \u2192 Add project from disk)`);
|
package/src/utils/templates.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync, copyFileSync, existsSync } from 'fs';
|
|
1
|
+
import { mkdirSync, writeFileSync, copyFileSync, existsSync, rmSync } from 'fs';
|
|
2
2
|
import { join, dirname } from 'path';
|
|
3
|
+
import { tmpdir } from 'os';
|
|
3
4
|
import { fileURLToPath } from 'url';
|
|
4
5
|
import { randomUUID } from 'crypto';
|
|
6
|
+
import * as tar from 'tar';
|
|
5
7
|
|
|
6
8
|
// Bundled starter cover art lives at src/assets/game-art/ (this file is at
|
|
7
9
|
// src/utils/). Resolved from the module path so it also works once the CLI is
|
|
@@ -14,6 +16,14 @@ const GAMEKIT_SDK_VERSION = '1.1.0-alpha.4';
|
|
|
14
16
|
const GAMEKIT_SDK_URL =
|
|
15
17
|
`https://github.com/MyVillage-Project-Technologies/myvillage-gamekit.git#v${GAMEKIT_SDK_VERSION}`;
|
|
16
18
|
|
|
19
|
+
// Direct (no-auth, no-redirect) tarball of the pinned tag. We download and
|
|
20
|
+
// unpack this into Packages/com.myvillage.gamekit/ at scaffold time so the
|
|
21
|
+
// project opens as a *local embedded package* — Unity never has to shell out to
|
|
22
|
+
// `git` to resolve the SDK. This is the fix for the "No 'git' executable was
|
|
23
|
+
// found" Package Manager error developers hit with a git-URL dependency.
|
|
24
|
+
const GAMEKIT_SDK_TARBALL_URL =
|
|
25
|
+
`https://codeload.github.com/MyVillage-Project-Technologies/myvillage-gamekit/tar.gz/refs/tags/v${GAMEKIT_SDK_VERSION}`;
|
|
26
|
+
|
|
17
27
|
// Fallback Unity Editor version used only if we can't fetch the SDK's
|
|
18
28
|
// package.json at scaffold time. The SDK declares the recommended editor
|
|
19
29
|
// version via `unity` + `unityRelease` fields — that's the source of truth.
|
|
@@ -41,6 +51,38 @@ async function resolveUnityVersion() {
|
|
|
41
51
|
}
|
|
42
52
|
}
|
|
43
53
|
|
|
54
|
+
// Download the pinned GameKit SDK tarball over HTTPS and unpack it into
|
|
55
|
+
// Packages/com.myvillage.gamekit/ so Unity treats it as a local embedded
|
|
56
|
+
// package — no `git` executable required to resolve it. Returns true on
|
|
57
|
+
// success; false (with the partial dir cleaned up) on any failure so the
|
|
58
|
+
// caller can fall back to the git-URL manifest entry and still scaffold.
|
|
59
|
+
async function embedGameKitSdk(targetDir) {
|
|
60
|
+
const pkgDir = join(targetDir, 'Packages', 'com.myvillage.gamekit');
|
|
61
|
+
const controller = new AbortController();
|
|
62
|
+
const timeout = setTimeout(() => controller.abort(), 20000);
|
|
63
|
+
let tmpFile;
|
|
64
|
+
try {
|
|
65
|
+
const res = await fetch(GAMEKIT_SDK_TARBALL_URL, { signal: controller.signal });
|
|
66
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
67
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
68
|
+
tmpFile = join(tmpdir(), `gamekit-${randomUUID()}.tar.gz`);
|
|
69
|
+
writeFileSync(tmpFile, buf);
|
|
70
|
+
mkdirSync(pkgDir, { recursive: true });
|
|
71
|
+
// strip:1 drops GitHub's top-level "<owner>-<repo>-<sha>/" wrapper folder
|
|
72
|
+
// so package.json lands at the root of pkgDir.
|
|
73
|
+
await tar.extract({ file: tmpFile, cwd: pkgDir, strip: 1 });
|
|
74
|
+
// Sanity check: a valid UPM package has package.json at its root.
|
|
75
|
+
if (!existsSync(join(pkgDir, 'package.json'))) throw new Error('package.json missing after extract');
|
|
76
|
+
return true;
|
|
77
|
+
} catch {
|
|
78
|
+
rmSync(pkgDir, { recursive: true, force: true });
|
|
79
|
+
return false;
|
|
80
|
+
} finally {
|
|
81
|
+
clearTimeout(timeout);
|
|
82
|
+
if (tmpFile) rmSync(tmpFile, { force: true });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
44
86
|
// MyVillage brand colors
|
|
45
87
|
const BRAND = {
|
|
46
88
|
gold: '#FFD700',
|
|
@@ -1135,7 +1177,7 @@ function generateUnityAgents(name, className, orientation) {
|
|
|
1135
1177
|
return [
|
|
1136
1178
|
'# AGENTS.md — working on this MyVillage Unity game with an AI agent',
|
|
1137
1179
|
'',
|
|
1138
|
-
'**' + name + '** is a MyVillage Unity game built on the **MyVillage GameKit SDK** (a UPM package
|
|
1180
|
+
'**' + name + '** is a MyVillage Unity game built on the **MyVillage GameKit SDK** (bundled as a local UPM package in `Packages/com.myvillage.gamekit/` — no git needed to open the project). The mission is C#; it builds to AssetBundles the M-UNI host loads.',
|
|
1139
1181
|
'',
|
|
1140
1182
|
'When editing: change the mission logic, keep the **game contract** intact (`CompleteMission` / `FailMission`), and do not break the GameKit `MissionBase` lifecycle.',
|
|
1141
1183
|
'',
|
|
@@ -1151,7 +1193,8 @@ function generateUnityAgents(name, className, orientation) {
|
|
|
1151
1193
|
'|------|---------|',
|
|
1152
1194
|
'| `Assets/Scripts/' + className + '.cs` | **Your mission** — the `MissionBase` subclass. Edit here. |',
|
|
1153
1195
|
'| `Assets/Editor/MyVillageOrientation.cs` | Pins player orientation on first load. |',
|
|
1154
|
-
'| `Packages/
|
|
1196
|
+
'| `Packages/com.myvillage.gamekit/` | The GameKit SDK, bundled as a local package. Do not hand-edit it. |',
|
|
1197
|
+
'| `Packages/manifest.json` | Unity registry packages (URP, TMP, Input System, …). |',
|
|
1155
1198
|
'| `myvillage.json` | Game metadata the CLI/deploy reads (slug, gameType, orientation, assets). |',
|
|
1156
1199
|
'| `assets/` | Cover art shipped on deploy (thumbnail/banner). |',
|
|
1157
1200
|
'| `builds/{ios,android,webgl}/` | Drop-zone for built AssetBundles the CLI deploys. |',
|
|
@@ -1181,7 +1224,7 @@ function generateUnityAgents(name, className, orientation) {
|
|
|
1181
1224
|
'',
|
|
1182
1225
|
'## Gotchas',
|
|
1183
1226
|
'',
|
|
1184
|
-
'- Do not edit the GameKit SDK package — it is
|
|
1227
|
+
'- Do not edit the GameKit SDK package — it is bundled in `Packages/com.myvillage.gamekit/`. Use its `MissionBase` API. To change SDK version, re-scaffold or replace that folder; do not patch it in place.',
|
|
1185
1228
|
'- Visual Scripting reflection nodes (`InvokeMember`/`GetMember`/`SetMember`) are rejected by the deploy preflight. Write C# instead.',
|
|
1186
1229
|
'',
|
|
1187
1230
|
].join('\n');
|
|
@@ -1199,12 +1242,14 @@ export async function createUnityGameProject(targetDir, options) {
|
|
|
1199
1242
|
const isLandscape = orientation === 'landscape';
|
|
1200
1243
|
const primaryGameType = isLandscape ? 'UNITY_WEBGL' : 'UNITY_NATIVE';
|
|
1201
1244
|
|
|
1202
|
-
// Scaffold an openable Unity project
|
|
1245
|
+
// Scaffold an openable Unity project with com.myvillage.gamekit bundled in
|
|
1246
|
+
// as a local embedded package (downloaded over HTTPS, no git required).
|
|
1203
1247
|
// Layout matches what Unity Hub expects:
|
|
1204
|
-
// Packages/
|
|
1248
|
+
// Packages/com.myvillage.gamekit/ - the GameKit SDK, embedded locally
|
|
1249
|
+
// Packages/manifest.json - Unity registry deps (URP, TMP, …)
|
|
1205
1250
|
// ProjectSettings/ProjectVersion.txt - tells Unity which editor version
|
|
1206
|
-
// Assets/Scripts/<Name>.cs
|
|
1207
|
-
// builds/{ios,android,webgl}/
|
|
1251
|
+
// Assets/Scripts/<Name>.cs - starter MissionBase subclass
|
|
1252
|
+
// builds/{ios,android,webgl}/ - drop-zone for builds the CLI deploys
|
|
1208
1253
|
|
|
1209
1254
|
const dirs = [
|
|
1210
1255
|
'',
|
|
@@ -1249,8 +1294,15 @@ export async function createUnityGameProject(targetDir, options) {
|
|
|
1249
1294
|
lastDeployed: null,
|
|
1250
1295
|
}, null, 2) + '\n');
|
|
1251
1296
|
|
|
1252
|
-
//
|
|
1253
|
-
|
|
1297
|
+
// Bundle the GameKit SDK as a local package so the project opens without git.
|
|
1298
|
+
// If the download fails (e.g. offline), fall back to the git-URL dependency in
|
|
1299
|
+
// the manifest — that path still works for anyone who has git installed.
|
|
1300
|
+
const sdkEmbedded = await embedGameKitSdk(targetDir);
|
|
1301
|
+
|
|
1302
|
+
// Unity project files. When the SDK is embedded it must NOT also be listed as
|
|
1303
|
+
// a manifest dependency (Unity would try to re-resolve it); when it isn't, the
|
|
1304
|
+
// git-URL entry is the fallback resolution path.
|
|
1305
|
+
writeFileSync(join(targetDir, 'Packages/manifest.json'), generateUnityPackagesManifest(sdkEmbedded));
|
|
1254
1306
|
writeFileSync(join(targetDir, 'ProjectSettings/ProjectVersion.txt'), generateUnityProjectVersion(unityVersion));
|
|
1255
1307
|
|
|
1256
1308
|
// Starter mission. New devs subclass MissionBase here.
|
|
@@ -1271,7 +1323,7 @@ export async function createUnityGameProject(targetDir, options) {
|
|
|
1271
1323
|
writeFileSync(join(targetDir, 'README.md'), generateUnityReadme(name, slug, className, orientation, unityVersion));
|
|
1272
1324
|
writeFileSync(join(targetDir, 'AGENTS.md'), generateUnityAgents(name, className, orientation));
|
|
1273
1325
|
|
|
1274
|
-
return { unityVersion, sdkVersion: GAMEKIT_SDK_VERSION, gameType: primaryGameType };
|
|
1326
|
+
return { unityVersion, sdkVersion: GAMEKIT_SDK_VERSION, gameType: primaryGameType, sdkEmbedded };
|
|
1275
1327
|
}
|
|
1276
1328
|
|
|
1277
1329
|
// Editor script: applies orientation to PlayerSettings on first load so a
|
|
@@ -1315,18 +1367,23 @@ public static class MyVillageOrientation
|
|
|
1315
1367
|
|
|
1316
1368
|
// ── Unity (GameKit SDK) ─────────────────────────────────────────────
|
|
1317
1369
|
|
|
1318
|
-
function generateUnityPackagesManifest() {
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1370
|
+
function generateUnityPackagesManifest(sdkEmbedded = true) {
|
|
1371
|
+
const dependencies = {};
|
|
1372
|
+
// Only declare the SDK as a git dependency when it could NOT be embedded
|
|
1373
|
+
// locally. When embedded under Packages/com.myvillage.gamekit/, Unity
|
|
1374
|
+
// auto-discovers it and listing it here would force a (git-based) re-resolve.
|
|
1375
|
+
if (!sdkEmbedded) {
|
|
1376
|
+
dependencies['com.myvillage.gamekit'] = GAMEKIT_SDK_URL;
|
|
1377
|
+
}
|
|
1378
|
+
Object.assign(dependencies, {
|
|
1379
|
+
'com.unity.feature.development': '1.0.2',
|
|
1380
|
+
'com.unity.render-pipelines.universal': '17.2.0',
|
|
1381
|
+
'com.unity.textmeshpro': '3.0.6',
|
|
1382
|
+
'com.unity.inputsystem': '1.14.2',
|
|
1383
|
+
'com.unity.ide.rider': '3.0.38',
|
|
1384
|
+
'com.unity.ide.visualstudio': '2.0.22',
|
|
1385
|
+
});
|
|
1386
|
+
return JSON.stringify({ dependencies }, null, 2) + '\n';
|
|
1330
1387
|
}
|
|
1331
1388
|
|
|
1332
1389
|
function generateUnityProjectVersion(unityVersion) {
|
|
@@ -1450,24 +1507,25 @@ A MyVillage game scaffolded with the MyVillage CLI and the MyVillage GameKit SDK
|
|
|
1450
1507
|
- **Slug:** \`${slug}\`
|
|
1451
1508
|
- **Game type:** \`${gameType}\`
|
|
1452
1509
|
- **Orientation:** \`${orientation}\` — plays on ${reach}
|
|
1453
|
-
- **SDK:** \`com.myvillage.gamekit\` (
|
|
1510
|
+
- **SDK:** \`com.myvillage.gamekit\` v${GAMEKIT_SDK_VERSION} (bundled in \`Packages/com.myvillage.gamekit/\` \u2014 no git required)
|
|
1454
1511
|
|
|
1455
1512
|
## What's in this project
|
|
1456
1513
|
|
|
1457
1514
|
\`\`\`
|
|
1458
1515
|
Assets/
|
|
1459
1516
|
\u2514\u2500\u2500 Scripts/
|
|
1460
|
-
\u2514\u2500\u2500 ${className}.cs
|
|
1517
|
+
\u2514\u2500\u2500 ${className}.cs \u2190 your mission, subclasses MissionBase
|
|
1461
1518
|
Packages/
|
|
1462
|
-
\
|
|
1519
|
+
\u251c\u2500\u2500 com.myvillage.gamekit/ \u2190 GameKit SDK, bundled locally
|
|
1520
|
+
\u2514\u2500\u2500 manifest.json \u2190 Unity registry packages (URP, TMP, \u2026)
|
|
1463
1521
|
ProjectSettings/
|
|
1464
1522
|
\u2514\u2500\u2500 ProjectVersion.txt
|
|
1465
|
-
myvillage.json
|
|
1523
|
+
myvillage.json \u2190 CLI metadata (auto-updated by deploy)
|
|
1466
1524
|
\`\`\`
|
|
1467
1525
|
|
|
1468
1526
|
## Quickstart \u2014 play your mission in 3 steps
|
|
1469
1527
|
|
|
1470
|
-
1. **Install Unity Hub** and Unity **${unityVersion}** if you don't have it. Open this folder in Unity Hub (Add \u2192 Add project from disk).
|
|
1528
|
+
1. **Install Unity Hub** and Unity **${unityVersion}** if you don't have it. Open this folder in Unity Hub (Add \u2192 Add project from disk). The GameKit SDK is already bundled in \`Packages/\`, so the project compiles on first open \u2014 you do **not** need git installed.
|
|
1471
1529
|
|
|
1472
1530
|
2. **Click the menu \`MyVillage \u2192 Create Starter Mission Scene\`.** This creates a new scene with a "Mission" GameObject that already has \`MockMissionHost\` attached (the editor stand-in for the real M-UNI host) and your \`${className}\` script auto-attached. The scene is added to Build Settings and opened for you.
|
|
1473
1531
|
|