launch-unity 0.7.0 → 0.9.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/README.ja.md +24 -16
- package/README.md +23 -29
- package/dist/launch.js +53 -6
- package/dist/unityHub.js +81 -1
- package/package.json +5 -5
package/README.ja.md
CHANGED
|
@@ -15,27 +15,35 @@ npm install -g launch-unity
|
|
|
15
15
|
npx launch-unity
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## 使い方
|
|
19
19
|
```bash
|
|
20
|
-
#
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
# 構文
|
|
21
|
+
launch-unity [OPTIONS] [PROJECT_PATH] [PLATFORM] [-- UNITY_ARGS...]
|
|
22
|
+
|
|
23
|
+
# 引数
|
|
24
|
+
# PROJECT_PATH Unityプロジェクトのディレクトリ(省略時は3階層下まで探索)
|
|
25
|
+
# PLATFORM Unityの -buildTarget に渡す値(例: StandaloneOSX, Android, iOS)
|
|
26
|
+
|
|
27
|
+
# オプション
|
|
28
|
+
# -h, --help ヘルプを表示
|
|
29
|
+
# -r, --restart Unityを再起動
|
|
30
|
+
# -a, -u, --add-unity-hub, --unity-hub-entry
|
|
31
|
+
# Unity Hub に登録(Unityは起動しない)
|
|
32
|
+
# -f, --favorite Unity Hub にお気に入りとして登録(Unityは起動しない)
|
|
33
|
+
|
|
34
|
+
# 例
|
|
35
|
+
npx launch-unity # プロジェクトを探索して開く
|
|
36
|
+
npx launch-unity /path/to/Proj # 指定プロジェクトを開く
|
|
37
|
+
npx launch-unity /path Android # ビルドターゲットを指定
|
|
38
|
+
npx launch-unity -r # Unityを再起動
|
|
39
|
+
npx launch-unity -a # Unity Hub に登録のみ(Unityは起動しない)
|
|
40
|
+
npx launch-unity -f # Unity Hub にお気に入り登録(Unityは起動しない)
|
|
41
|
+
npx launch-unity . -- -batchmode -quit -nographics -logFile - # Unity引数を渡す
|
|
28
42
|
npx launch-unity /path Android -- -executeMethod My.Build.Entry
|
|
29
|
-
|
|
30
|
-
# グローバルインストール後
|
|
31
|
-
launch-unity
|
|
32
|
-
launch-unity /path/to/MyUnityProject Android
|
|
33
|
-
launch-unity . -- -buildTarget iOS -projectPath . # 上書きも可能
|
|
34
43
|
```
|
|
35
44
|
|
|
36
45
|
指定した Unity プロジェクトの `ProjectSettings/ProjectVersion.txt` から必要な Unity Editor のバージョンを読み取り、
|
|
37
|
-
Unity Hub でインストール済みの該当バージョンを起動する macOS/Windows 向け TypeScript 製 CLI
|
|
38
|
-
存在する場合は、削除して続行するかをターミナル上で確認します。
|
|
46
|
+
Unity Hub でインストール済みの該当バージョンを起動する macOS/Windows 向け TypeScript 製 CLI です。
|
|
39
47
|
|
|
40
48
|
既定で想定する Unity のパス:
|
|
41
49
|
- macOS: `/Applications/Unity/Hub/Editor/<version>/Unity.app/Contents/MacOS/Unity`
|
package/README.md
CHANGED
|
@@ -15,28 +15,36 @@ npm install -g launch-unity
|
|
|
15
15
|
npx launch-unity
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
## Usage
|
|
18
|
+
## Usage
|
|
19
19
|
```bash
|
|
20
|
-
#
|
|
21
|
-
|
|
22
|
-
npx launch-unity /path/to/Proj # Open a specific project
|
|
23
|
-
npx launch-unity /path Android # Specify build target
|
|
24
|
-
npx -y launch-unity # Skip npx "Ok to proceed?" prompt
|
|
20
|
+
# Syntax
|
|
21
|
+
launch-unity [OPTIONS] [PROJECT_PATH] [PLATFORM] [-- UNITY_ARGS...]
|
|
25
22
|
|
|
26
|
-
#
|
|
27
|
-
|
|
23
|
+
# Arguments
|
|
24
|
+
# PROJECT_PATH Unity project directory (searches up to 3 levels deep if omitted)
|
|
25
|
+
# PLATFORM Passed to Unity as -buildTarget (e.g., StandaloneOSX, Android, iOS)
|
|
26
|
+
|
|
27
|
+
# Options
|
|
28
|
+
# -h, --help Show help
|
|
29
|
+
# -r, --restart Kill running Unity and restart
|
|
30
|
+
# -a, -u, --add-unity-hub, --unity-hub-entry
|
|
31
|
+
# Register to Unity Hub (does not launch Unity)
|
|
32
|
+
# -f, --favorite Register to Unity Hub as favorite (does not launch Unity)
|
|
33
|
+
|
|
34
|
+
# Examples
|
|
35
|
+
npx launch-unity # Search for project and open
|
|
36
|
+
npx launch-unity /path/to/Proj # Open specific project
|
|
37
|
+
npx launch-unity /path Android # Specify build target
|
|
38
|
+
npx launch-unity -r # Restart Unity
|
|
39
|
+
npx launch-unity -a # Register to Unity Hub only (does not launch Unity)
|
|
40
|
+
npx launch-unity -f # Register as favorite (does not launch Unity)
|
|
41
|
+
npx launch-unity . -- -batchmode -quit -nographics -logFile - # Pass Unity args
|
|
28
42
|
npx launch-unity /path Android -- -executeMethod My.Build.Entry
|
|
29
|
-
|
|
30
|
-
# Installed globally
|
|
31
|
-
launch-unity
|
|
32
|
-
launch-unity /path/to/MyUnityProject Android
|
|
33
|
-
launch-unity . -- -buildTarget iOS -projectPath . # You can override
|
|
34
43
|
```
|
|
35
44
|
|
|
36
45
|
A TypeScript CLI for macOS and Windows that reads the required Unity Editor version from
|
|
37
46
|
`ProjectSettings/ProjectVersion.txt`, launches the matching Unity installed via Unity Hub,
|
|
38
|
-
and opens the project.
|
|
39
|
-
delete it before continuing.
|
|
47
|
+
and opens the project.
|
|
40
48
|
|
|
41
49
|
Default Unity paths assumed:
|
|
42
50
|
- macOS: `/Applications/Unity/Hub/Editor/<version>/Unity.app/Contents/MacOS/Unity`
|
|
@@ -47,20 +55,6 @@ Default Unity paths assumed:
|
|
|
47
55
|
- `C:\\Program Files\\Unity\\Hub\\Editor\\<version>\\Editor\\Unity.exe`
|
|
48
56
|
|
|
49
57
|
|
|
50
|
-
## Detailed Usage
|
|
51
|
-
```bash
|
|
52
|
-
# Basic syntax
|
|
53
|
-
launch-unity [PROJECT_PATH] [PLATFORM]
|
|
54
|
-
|
|
55
|
-
# Arguments
|
|
56
|
-
# - PROJECT_PATH (optional): Unity project directory. Defaults to current directory
|
|
57
|
-
# - PLATFORM (optional): Passed to Unity as -buildTarget (e.g., StandaloneOSX, Android, iOS)
|
|
58
|
-
|
|
59
|
-
# Flags
|
|
60
|
-
# -h, --help Show help
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
|
|
64
58
|
## Troubleshooting
|
|
65
59
|
- Error: `ProjectVersion.txt not found`
|
|
66
60
|
- The provided directory is not a Unity project. Point to the project root.
|
package/dist/launch.js
CHANGED
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
import { execFile, spawn } from "node:child_process";
|
|
7
7
|
import { existsSync, readFileSync, readdirSync, lstatSync, realpathSync } from "node:fs";
|
|
8
8
|
import { rm } from "node:fs/promises";
|
|
9
|
-
import { join, resolve } from "node:path";
|
|
9
|
+
import { dirname, join, resolve } from "node:path";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
10
11
|
import { promisify } from "node:util";
|
|
11
|
-
import { updateLastModifiedIfExists } from "./unityHub.js";
|
|
12
|
+
import { ensureProjectEntryAndUpdate, updateLastModifiedIfExists } from "./unityHub.js";
|
|
12
13
|
const execFileAsync = promisify(execFile);
|
|
13
14
|
const UNITY_EXECUTABLE_PATTERN_MAC = /Unity\.app\/Contents\/MacOS\/Unity/i;
|
|
14
15
|
const UNITY_EXECUTABLE_PATTERN_WINDOWS = /Unity\.exe/i;
|
|
@@ -26,16 +27,33 @@ function parseArgs(argv) {
|
|
|
26
27
|
const positionals = [];
|
|
27
28
|
let maxDepth = 3; // default 3; -1 means unlimited
|
|
28
29
|
let restart = false;
|
|
30
|
+
let addUnityHub = false;
|
|
31
|
+
let favoriteUnityHub = false;
|
|
29
32
|
for (let i = 0; i < cliArgs.length; i++) {
|
|
30
33
|
const arg = cliArgs[i] ?? "";
|
|
31
34
|
if (arg === "--help" || arg === "-h") {
|
|
32
35
|
printHelp();
|
|
33
36
|
process.exit(0);
|
|
34
37
|
}
|
|
38
|
+
if (arg === "--version" || arg === "-v") {
|
|
39
|
+
console.log(getVersion());
|
|
40
|
+
process.exit(0);
|
|
41
|
+
}
|
|
35
42
|
if (arg === "-r" || arg === "--restart") {
|
|
36
43
|
restart = true;
|
|
37
44
|
continue;
|
|
38
45
|
}
|
|
46
|
+
if (arg === "-u" ||
|
|
47
|
+
arg === "-a" ||
|
|
48
|
+
arg === "--unity-hub-entry" ||
|
|
49
|
+
arg === "--add-unity-hub") {
|
|
50
|
+
addUnityHub = true;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (arg === "-f" || arg === "--favorite") {
|
|
54
|
+
favoriteUnityHub = true;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
39
57
|
if (arg.startsWith("--max-depth")) {
|
|
40
58
|
const parts = arg.split("=");
|
|
41
59
|
if (parts.length === 2) {
|
|
@@ -84,7 +102,7 @@ function parseArgs(argv) {
|
|
|
84
102
|
projectPath = resolve(positionals[0] ?? "");
|
|
85
103
|
platform = String(positionals[1] ?? "");
|
|
86
104
|
}
|
|
87
|
-
const options = { unityArgs, searchMaxDepth: maxDepth, restart };
|
|
105
|
+
const options = { unityArgs, searchMaxDepth: maxDepth, restart, addUnityHub, favoriteUnityHub };
|
|
88
106
|
if (projectPath !== undefined) {
|
|
89
107
|
options.projectPath = projectPath;
|
|
90
108
|
}
|
|
@@ -93,6 +111,13 @@ function parseArgs(argv) {
|
|
|
93
111
|
}
|
|
94
112
|
return options;
|
|
95
113
|
}
|
|
114
|
+
function getVersion() {
|
|
115
|
+
const currentFilePath = fileURLToPath(import.meta.url);
|
|
116
|
+
const currentDir = dirname(currentFilePath);
|
|
117
|
+
const packageJsonPath = join(currentDir, "..", "package.json");
|
|
118
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
119
|
+
return packageJson.version;
|
|
120
|
+
}
|
|
96
121
|
function printHelp() {
|
|
97
122
|
const help = `
|
|
98
123
|
Usage: launch-unity [PROJECT_PATH] [PLATFORM] -- [UNITY_ARGS...]
|
|
@@ -109,8 +134,12 @@ Forwarding:
|
|
|
109
134
|
|
|
110
135
|
Flags:
|
|
111
136
|
-h, --help Show this help message
|
|
137
|
+
-v, --version Show version number
|
|
112
138
|
-r, --restart Kill running Unity and restart
|
|
113
139
|
--max-depth <N> Search depth when PROJECT_PATH is omitted (default 3, -1 unlimited)
|
|
140
|
+
-u, -a, --unity-hub-entry, --add-unity-hub
|
|
141
|
+
Add to Unity Hub if missing and update lastModified (does not launch Unity)
|
|
142
|
+
-f, --favorite Add to Unity Hub as favorite (does not launch Unity)
|
|
114
143
|
`;
|
|
115
144
|
process.stdout.write(help);
|
|
116
145
|
}
|
|
@@ -538,8 +567,7 @@ function findUnityProjectBfs(rootDir, maxDepth) {
|
|
|
538
567
|
return undefined;
|
|
539
568
|
}
|
|
540
569
|
function launch(opts) {
|
|
541
|
-
const { projectPath, platform, unityArgs } = opts;
|
|
542
|
-
const unityVersion = getUnityVersion(projectPath);
|
|
570
|
+
const { projectPath, platform, unityArgs, unityVersion } = opts;
|
|
543
571
|
const unityPath = getUnityPath(unityVersion);
|
|
544
572
|
console.log(`Detected Unity version: ${unityVersion}`);
|
|
545
573
|
if (!existsSync(unityPath)) {
|
|
@@ -577,6 +605,23 @@ async function main() {
|
|
|
577
605
|
resolvedProjectPath = found;
|
|
578
606
|
}
|
|
579
607
|
ensureProjectPath(resolvedProjectPath);
|
|
608
|
+
const unityVersion = getUnityVersion(resolvedProjectPath);
|
|
609
|
+
// Unity Hub only mode: -a or -f flags skip launching Unity
|
|
610
|
+
const unityHubOnlyMode = options.addUnityHub || options.favoriteUnityHub;
|
|
611
|
+
if (unityHubOnlyMode) {
|
|
612
|
+
console.log(`Detected Unity version: ${unityVersion}`);
|
|
613
|
+
console.log(`Project Path: ${resolvedProjectPath}`);
|
|
614
|
+
const now = new Date();
|
|
615
|
+
try {
|
|
616
|
+
await ensureProjectEntryAndUpdate(resolvedProjectPath, unityVersion, now, options.favoriteUnityHub);
|
|
617
|
+
console.log("Unity Hub entry updated.");
|
|
618
|
+
}
|
|
619
|
+
catch (error) {
|
|
620
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
621
|
+
console.warn(`Failed to update Unity Hub: ${message}`);
|
|
622
|
+
}
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
580
625
|
if (options.restart) {
|
|
581
626
|
await killRunningUnity(resolvedProjectPath);
|
|
582
627
|
}
|
|
@@ -594,11 +639,13 @@ async function main() {
|
|
|
594
639
|
projectPath: resolvedProjectPath,
|
|
595
640
|
platform: options.platform,
|
|
596
641
|
unityArgs: options.unityArgs,
|
|
642
|
+
unityVersion,
|
|
597
643
|
};
|
|
598
644
|
launch(resolved);
|
|
599
645
|
// Best-effort update of Unity Hub's lastModified timestamp.
|
|
646
|
+
const now = new Date();
|
|
600
647
|
try {
|
|
601
|
-
await updateLastModifiedIfExists(resolvedProjectPath,
|
|
648
|
+
await updateLastModifiedIfExists(resolvedProjectPath, now);
|
|
602
649
|
}
|
|
603
650
|
catch (error) {
|
|
604
651
|
const message = error instanceof Error ? error.message : String(error);
|
package/dist/unityHub.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFile, writeFile } from "node:fs/promises";
|
|
2
|
-
import {
|
|
2
|
+
import { realpathSync } from "node:fs";
|
|
3
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
3
4
|
const resolveUnityHubProjectFiles = () => {
|
|
4
5
|
if (process.platform === "darwin") {
|
|
5
6
|
const home = process.env.HOME;
|
|
@@ -30,12 +31,91 @@ const normalizePath = (target) => {
|
|
|
30
31
|
const resolvedPath = resolve(target);
|
|
31
32
|
return removeTrailingSeparators(resolvedPath);
|
|
32
33
|
};
|
|
34
|
+
const resolvePathWithActualCase = (target) => {
|
|
35
|
+
try {
|
|
36
|
+
return removeTrailingSeparators(realpathSync.native(target));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return normalizePath(target);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
33
42
|
const toComparablePath = (value) => {
|
|
34
43
|
return value.replace(/\\/g, "/").toLocaleLowerCase();
|
|
35
44
|
};
|
|
36
45
|
const pathsEqual = (left, right) => {
|
|
37
46
|
return toComparablePath(normalizePath(left)) === toComparablePath(normalizePath(right));
|
|
38
47
|
};
|
|
48
|
+
const safeParseProjectsJson = (content) => {
|
|
49
|
+
try {
|
|
50
|
+
return JSON.parse(content);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const logDebug = (message) => {
|
|
57
|
+
if (process.env["LAUNCH_UNITY_DEBUG"] === "1") {
|
|
58
|
+
console.log(`[unityHub] ${message}`);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
export const ensureProjectEntryAndUpdate = async (projectPath, version, when, setFavorite = false) => {
|
|
62
|
+
const canonicalProjectPath = resolvePathWithActualCase(projectPath);
|
|
63
|
+
const projectTitle = basename(canonicalProjectPath);
|
|
64
|
+
const containingFolderPath = dirname(canonicalProjectPath);
|
|
65
|
+
const candidates = resolveUnityHubProjectFiles();
|
|
66
|
+
if (candidates.length === 0) {
|
|
67
|
+
logDebug("No Unity Hub project files found.");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
for (const path of candidates) {
|
|
71
|
+
logDebug(`Trying Unity Hub file: ${path}`);
|
|
72
|
+
const content = await readFile(path, "utf8").catch(() => undefined);
|
|
73
|
+
if (!content) {
|
|
74
|
+
logDebug("Read failed or empty content, skipping.");
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const json = safeParseProjectsJson(content);
|
|
78
|
+
if (!json) {
|
|
79
|
+
logDebug("Parse failed, skipping.");
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const data = { ...(json.data ?? {}) };
|
|
83
|
+
const existingKey = Object.keys(data).find((key) => {
|
|
84
|
+
const entryPath = data[key]?.path;
|
|
85
|
+
return entryPath ? pathsEqual(entryPath, projectPath) : false;
|
|
86
|
+
});
|
|
87
|
+
const targetKey = existingKey ?? canonicalProjectPath;
|
|
88
|
+
const existingEntry = existingKey ? data[existingKey] : undefined;
|
|
89
|
+
logDebug(existingKey
|
|
90
|
+
? `Found existing entry for project (key=${existingKey}). Updating lastModified.`
|
|
91
|
+
: `No existing entry. Adding new entry (key=${targetKey}).`);
|
|
92
|
+
const updatedEntry = {
|
|
93
|
+
...existingEntry,
|
|
94
|
+
path: existingEntry?.path ?? canonicalProjectPath,
|
|
95
|
+
containingFolderPath: existingEntry?.containingFolderPath ?? containingFolderPath,
|
|
96
|
+
version: existingEntry?.version ?? version,
|
|
97
|
+
title: existingEntry?.title ?? projectTitle,
|
|
98
|
+
lastModified: when.getTime(),
|
|
99
|
+
isFavorite: setFavorite ? true : (existingEntry?.isFavorite ?? false),
|
|
100
|
+
};
|
|
101
|
+
const updatedJson = {
|
|
102
|
+
...json,
|
|
103
|
+
data: {
|
|
104
|
+
...data,
|
|
105
|
+
[targetKey]: updatedEntry,
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
try {
|
|
109
|
+
await writeFile(path, JSON.stringify(updatedJson, undefined, 2), "utf8");
|
|
110
|
+
logDebug("Write succeeded.");
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
logDebug(`Write failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
114
|
+
// Ignore write errors to avoid breaking CLI flow
|
|
115
|
+
}
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
39
119
|
export const updateLastModifiedIfExists = async (projectPath, when) => {
|
|
40
120
|
const candidates = resolveUnityHubProjectFiles();
|
|
41
121
|
if (candidates.length === 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "launch-unity",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Open a Unity project with the matching Editor version (macOS/Windows)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/launch.js",
|
|
@@ -39,15 +39,15 @@
|
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/node": "24.10.1",
|
|
42
|
-
"@typescript-eslint/eslint-plugin": "8.48.
|
|
43
|
-
"@typescript-eslint/parser": "8.48.
|
|
42
|
+
"@typescript-eslint/eslint-plugin": "8.48.1",
|
|
43
|
+
"@typescript-eslint/parser": "8.48.1",
|
|
44
44
|
"eslint": "9.39.1",
|
|
45
45
|
"eslint-config-prettier": "10.1.8",
|
|
46
|
-
"prettier": "3.7.
|
|
46
|
+
"prettier": "3.7.4",
|
|
47
47
|
"typescript": "5.9.3"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"typescript-eslint": "8.48.
|
|
50
|
+
"typescript-eslint": "8.48.1"
|
|
51
51
|
},
|
|
52
52
|
"overrides": {
|
|
53
53
|
"js-yaml": "4.1.1"
|