initial commit

This commit is contained in:
Lillith Rose (Device: Lucia) 2025-06-28 14:44:05 -04:00
commit f29cef440f
3 changed files with 128 additions and 0 deletions

15
action.yml Normal file
View file

@ -0,0 +1,15 @@
name: Create UnityPackage
description: Create a .unitypackage from Unity project files with .meta files
inputs:
projectDir:
description: Path to the root of your Unity project
required: true
filesDir:
description: Subfolder to pack (relative to projectDir)
required: true
output:
description: Output path for the .unitypackage file
required: true
runs:
using: "node20"
main: "index.js"

103
index.js Normal file
View file

@ -0,0 +1,103 @@
import {
mkdirSync,
mkdtempSync,
readdirSync,
createReadStream,
createWriteStream,
existsSync,
} from "fs";
import { copyFile, readFile, writeFile, rm } from "fs/promises";
import { tmpdir } from "os";
import { join } from "path";
import * as tar from "tar-stream";
import { createGzip } from "zlib";
import { parse as yamlParse } from "yaml";
const projectDir = process.env["INPUT_PROJECTDIR"];
const filesDir = process.env["INPUT_FILESDIR"];
const output = process.env["INPUT_OUTPUT"];
if (!projectDir || !filesDir || !output) {
console.error("Missing required input(s).");
process.exit(1);
}
const tempdir = (name) => {
const dir = mkdtempSync(join(tmpdir(), name));
return dir;
};
const mkdir = (dir, recursive = false) => {
mkdirSync(dir, { recursive });
return dir;
};
const getMetaFiles = (root) => {
const recurse = (dir) => {
const entries = readdirSync(join(root, dir), { withFileTypes: true });
let files = [];
for (const entry of entries) {
const fullPath = join(dir, entry.name);
if (entry.isDirectory()) {
files = files.concat(recurse(fullPath));
} else if (entry.name.endsWith(".meta")) {
files.push(fullPath);
}
}
return files;
};
return recurse(".");
};
const createUnityPackage = async () => {
const metaFiles = getMetaFiles(join(projectDir, filesDir));
const tempDir = tempdir("unitypackage-create-");
for await (const metaFile of metaFiles) {
const assetPath = metaFile.replace(/\.meta$/, "");
const metaPath = join(projectDir, filesDir, metaFile);
const meta = yamlParse(await readFile(metaPath, "utf8"));
const guid = meta.guid;
if (!guid) continue;
const dir = mkdir(join(tempDir, guid), true);
const assetFullPath = join(projectDir, filesDir, assetPath);
if (!meta.folderAsset && existsSync(assetFullPath)) {
await copyFile(assetFullPath, join(dir, "asset"));
}
await copyFile(metaPath, join(dir, "asset.meta"));
await writeFile(join(dir, "pathname"), join(filesDir, assetPath));
}
const pack = tar.pack();
for (const guidDir of readdirSync(tempDir)) {
const entryDir = join(tempDir, guidDir);
for (const entry of readdirSync(entryDir)) {
const filePath = join(entryDir, entry);
const stream = createReadStream(filePath);
const buffer = await new Promise((resolve) => {
const chunks = [];
stream.on("data", (chunk) => chunks.push(chunk));
stream.on("end", () => resolve(Buffer.concat(chunks)));
});
pack.entry({ name: join(guidDir, entry), type: "file" }, buffer);
}
}
pack.finalize();
const writeStream = createWriteStream(output);
pack.pipe(createGzip()).pipe(writeStream);
await new Promise((resolve, reject) => {
writeStream.on("finish", resolve);
writeStream.on("error", reject);
});
await rm(tempDir, { recursive: true, force: true });
console.log(`UnityPackage created: ${output}`);
};
createUnityPackage();

10
package.json Normal file
View file

@ -0,0 +1,10 @@
{
"name": "create-unitypackage-action",
"type": "module",
"main": "index.js",
"dependencies": {
"tar-stream": "^3.1.7",
"yaml": "^2.3.4"
}
}