forked from phenom/healer-man
Update Healer Man server
This commit is contained in:
1 parent
6114a2295f
commit
69809f7228
593 files changed
+903643
-40774
No files matched your search
@@ -1,7 +1,9 @@
|
||||
import { spawn } from "node:child_process";
|
||||
import { stat } from "node:fs/promises";
|
||||
import { copyFile, mkdtemp, rm, stat } from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { exists, loadRecipe, projectRoot, readJson, workRoot, writeJson } from "./lib.mjs";
|
||||
import { preprocessShadowfangVisual } from "./shadowfang-fallback-preprocess.mjs";
|
||||
|
||||
function runCli(args) {
|
||||
const cli = path.join(projectRoot, "node_modules/@gltf-transform/cli/bin/cli.js");
|
||||
@@ -30,19 +32,11 @@ function compressKtx2(file) {
|
||||
});
|
||||
}
|
||||
|
||||
export async function optimizeDungeonEnvironment(slug) {
|
||||
await loadRecipe(slug);
|
||||
const directory = path.join(workRoot, slug, "staging", "environment");
|
||||
const conversionFile = path.join(directory, "conversion-report.json");
|
||||
if (!await exists(conversionFile)) return { status: "blocked", dungeonId: slug, blockers: ["Run dungeon:convert first."] };
|
||||
const conversion = await readJson(conversionFile);
|
||||
const source = path.join(directory, conversion.visual.file);
|
||||
if (!await exists(source)) return { status: "blocked", dungeonId: slug, blockers: ["The lossless visual GLB is missing."] };
|
||||
const optimized = path.join(directory, `${slug}-visual.optimized.glb`);
|
||||
await runCli([
|
||||
export function dungeonEnvironmentOptimizationArguments(sourceFile, outputFile) {
|
||||
return [
|
||||
"optimize",
|
||||
source,
|
||||
optimized,
|
||||
sourceFile,
|
||||
outputFile,
|
||||
"--compress",
|
||||
"meshopt",
|
||||
"--meshopt-level",
|
||||
@@ -51,22 +45,84 @@ export async function optimizeDungeonEnvironment(slug) {
|
||||
"true",
|
||||
"--instance-min",
|
||||
"3",
|
||||
"--texture-size",
|
||||
"2048",
|
||||
]);
|
||||
await compressKtx2(optimized);
|
||||
const report = {
|
||||
schemaVersion: 1,
|
||||
dungeonId: slug,
|
||||
status: "review-required",
|
||||
source: { file: path.basename(source), size: (await stat(source)).size },
|
||||
optimized: { file: path.basename(optimized), size: (await stat(optimized)).size },
|
||||
compression: "meshopt+ktx2",
|
||||
commands: [
|
||||
"gltf-transform optimize --compress meshopt --meshopt-level high --instance true --instance-min 3 --texture-size 2048",
|
||||
"node scripts/asset-pipeline/compress-ktx2.mjs <optimized.glb> --concurrency 1 --jobs 2",
|
||||
],
|
||||
};
|
||||
await writeJson(path.join(directory, "optimization-report.json"), report);
|
||||
return report;
|
||||
"--simplify",
|
||||
"false",
|
||||
"--texture-compress",
|
||||
"false",
|
||||
];
|
||||
}
|
||||
|
||||
export function dungeonEnvironmentFinalPackingArguments(sourceFile, outputFile) {
|
||||
return dungeonEnvironmentOptimizationArguments(sourceFile, outputFile);
|
||||
}
|
||||
|
||||
export async function optimizeDungeonEnvironment(slug) {
|
||||
const recipe = await loadRecipe(slug);
|
||||
const directory = path.join(workRoot, slug, "staging", "environment");
|
||||
const conversionFile = path.join(directory, "conversion-report.json");
|
||||
if (!await exists(conversionFile)) return { status: "blocked", dungeonId: slug, blockers: ["Run dungeon:convert first."] };
|
||||
const conversion = await readJson(conversionFile);
|
||||
const source = path.join(directory, conversion.visual.file);
|
||||
if (!await exists(source)) return { status: "blocked", dungeonId: slug, blockers: ["The lossless visual GLB is missing."] };
|
||||
const selectiveProfile = recipe.visualOptimization?.selectiveFallbackSimplification;
|
||||
if (slug === "shadowfang-keep" && !selectiveProfile) {
|
||||
throw new Error("Shadowfang optimization requires its source-pinned selective fallback recipe profile.");
|
||||
}
|
||||
if (slug !== "shadowfang-keep" && selectiveProfile) {
|
||||
throw new Error(`The Shadowfang-only selective fallback profile cannot be applied to ${slug}.`);
|
||||
}
|
||||
const optimized = path.join(directory, `${slug}-visual.optimized.glb`);
|
||||
const packed = path.join(directory, `${slug}-visual.meshopt-final.glb`);
|
||||
let temporaryDirectory = null;
|
||||
let optimizationSource = source;
|
||||
let sourcePreprocessing = null;
|
||||
try {
|
||||
if (slug === "shadowfang-keep") {
|
||||
temporaryDirectory = await mkdtemp(path.join(os.tmpdir(), "shadowfang-optimizer-source-"));
|
||||
optimizationSource = path.join(temporaryDirectory, "shadowfang-selective-source.glb");
|
||||
sourcePreprocessing = await preprocessShadowfangVisual(source, optimizationSource);
|
||||
}
|
||||
|
||||
await runCli(dungeonEnvironmentOptimizationArguments(optimizationSource, optimized));
|
||||
await compressKtx2(optimized);
|
||||
await rm(packed, { force: true });
|
||||
await runCli(dungeonEnvironmentFinalPackingArguments(optimized, packed));
|
||||
await copyFile(packed, optimized);
|
||||
await rm(packed, { force: true });
|
||||
const finalPackingCommand = "gltf-transform optimize <optimized.glb> <meshopt-final.glb> --compress meshopt --meshopt-level high --instance true --instance-min 3 --simplify false --texture-compress false";
|
||||
const report = {
|
||||
schemaVersion: 1,
|
||||
dungeonId: slug,
|
||||
status: "review-required",
|
||||
source: { file: path.basename(source), size: (await stat(source)).size },
|
||||
sourcePreprocessing: sourcePreprocessing ? {
|
||||
method: "source-pinned selective simplification of untextured ADT_Terrain and ADT_Liquid_B2 fallback materials",
|
||||
sourceSha256: sourcePreprocessing.source.sha256,
|
||||
texturedPrimitiveAccessorHashesUnchanged: sourcePreprocessing.texturedPrimitiveAccessorHashesUnchanged,
|
||||
sourceTextureBytesUnchanged: sourcePreprocessing.sourceTextureBytesUnchanged,
|
||||
...sourcePreprocessing.profile,
|
||||
selectedByMaterial: sourcePreprocessing.selectedByMaterial,
|
||||
} : null,
|
||||
optimized: { file: path.basename(optimized), size: (await stat(optimized)).size },
|
||||
compression: "meshopt+ktx2",
|
||||
meshoptPackingRestoredAfterTextureCompression: true,
|
||||
finalPackedStage: {
|
||||
status: "complete",
|
||||
file: path.basename(optimized),
|
||||
size: (await stat(optimized)).size,
|
||||
extension: "EXT_meshopt_compression",
|
||||
command: finalPackingCommand,
|
||||
},
|
||||
commands: [
|
||||
...(sourcePreprocessing ? ["source-pinned Shadowfang fallback preprocessing (see sourcePreprocessing profile)"] : []),
|
||||
"gltf-transform optimize --compress meshopt --meshopt-level high --instance true --instance-min 3 --simplify false --texture-compress false",
|
||||
"node scripts/asset-pipeline/compress-ktx2.mjs <optimized.glb> --concurrency 1 --jobs 2",
|
||||
finalPackingCommand,
|
||||
],
|
||||
};
|
||||
await writeJson(path.join(directory, "optimization-report.json"), report);
|
||||
return report;
|
||||
} finally {
|
||||
if (temporaryDirectory) await rm(temporaryDirectory, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user