feat(housekeeping): integrate studio operations
CI / check (pull_request) Successful in 38s
CI / release (pull_request) Skipped
CI / deploy (pull_request) Skipped

This commit is contained in:
Simo committed 2026-08-30 15:29:58 +02:00
1 parent 020c06f172
commit 2e95a106e0
36 files changed
+2296 -60

No files matched your search

+18 -4
View File
@@ -403,10 +403,13 @@ async function syncDirMissingFiles(
* so all imported furniture stays renderable in-game even when a mirror
* write was skipped.
*/
export async function syncAssetsToGamedataBundle(): Promise<{
export async function syncAssetsToGamedataBundle(
signal?: AbortSignal,
): Promise<{
copiedNitros: string[];
copiedIcons: string[];
}> {
signal?.throwIfAborted();
if (process.platform === "win32")
return { copiedNitros: [], copiedIcons: [] };
@@ -423,6 +426,7 @@ export async function syncAssetsToGamedataBundle(): Promise<{
"bundled/furniture",
);
if (nitroDir !== nitroTarget) {
signal?.throwIfAborted();
const copied = await syncDirMissingFiles(nitroDir, nitroTarget, (entry) =>
entry.endsWith(".nitro"),
);
@@ -434,6 +438,7 @@ export async function syncAssetsToGamedataBundle(): Promise<{
"icons",
);
if (iconDir !== iconTarget) {
signal?.throwIfAborted();
const copied = await syncDirMissingFiles(iconDir, iconTarget, (entry) =>
entry.endsWith("_icon.png"),
);
@@ -508,6 +513,7 @@ export async function importSingleFurni(params: {
skipFurniDataWrite?: boolean;
updateExisting?: boolean;
onProgress?: (status: string) => void;
signal?: AbortSignal;
/** Per-source SWF download base URL (e.g. "https://virtualc.nl/dcr"). */
sourceSwfBaseUrl?: string;
/** Per-source nitro bundle + icon base URL. */
@@ -525,10 +531,12 @@ export async function importSingleFurni(params: {
skipFurniDataWrite,
updateExisting,
onProgress,
signal,
sourceSwfBaseUrl,
nitroBaseUrl: sourceNitroBaseUrl,
iconBaseUrl: sourceIconBaseUrl,
} = params;
signal?.throwIfAborted();
const warnings: string[] = [];
// Check if already exists by classname OR by spriteId (primary key collision).
@@ -604,6 +612,7 @@ export async function importSingleFurni(params: {
// ── Insert into DB with enriched data ──────────────────────────────
onProgress?.("writing_db");
signal?.throwIfAborted();
try {
if (isUpdate) {
// NOTE: live Arcturus `items_base` has no description/revision/rare columns —
@@ -660,6 +669,7 @@ export async function importSingleFurni(params: {
// fall back to base-classname icon (Nitro reuses base for all colors
// when no color-specific icon exists).
onProgress?.("downloading");
signal?.throwIfAborted();
const iconColorAware = classname.replace(/\*/g, "_");
@@ -701,8 +711,8 @@ export async function importSingleFurni(params: {
// Download icon + SWF concurrently (independent assets). Each tries its
// candidate URLs in order until one succeeds.
const [iconOkResult, swfOk] = await Promise.all([
tryDownloadCandidates(iconUrls, iconPath, "png"),
tryDownloadCandidates(swfUrls, swfPath, "swf"),
tryDownloadCandidates(iconUrls, iconPath, "png", signal),
tryDownloadCandidates(swfUrls, swfPath, "swf", signal),
]);
let iconOk = iconOkResult;
@@ -715,7 +725,10 @@ export async function importSingleFurni(params: {
!existsSync(/*turbopackIgnore: true*/ nitroPath)
) {
const nitroUrl = `${sourceNitroBaseUrl}/${encodeURIComponent(safeNitroName)}.nitro`;
const dl = await downloadFile(nitroUrl, nitroPath, { validate: "png" });
const dl = await downloadFile(nitroUrl, nitroPath, {
validate: "png",
signal,
});
if (dl.ok) nitroDownloadOk = true;
}
@@ -744,6 +757,7 @@ export async function importSingleFurni(params: {
// ── Convert SWF to Nitro ──────────────────────────────────────────
onProgress?.("converting");
signal?.throwIfAborted();
let conversionResult: ConversionResult | null = null;
if (existsSync(/*turbopackIgnore: true*/ nitroPath)) {