Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 1.4.0

- Fix: `gm-cli package` now works correctly on Linux.
- New feature: Configurable package format for Windows (`zip` or `nsis`), macOS (`zip` or `dmg`), and Linux (`zip` or `appimage`) via `gm-options.json` or `--toolchain-options`. Example: `--toolchain-options '{"windows": {"packageType": "nsis"}}'`.

# 1.3.0

- Fix: Create blank games with latest ResourceTool release
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"url": "https://github.com/YoYoGames/gm-cli"
},
"type": "module",
"version": "1.3.0",
"version": "1.4.0",
"files": [
"dist",
"NOTICE"
Expand Down
8 changes: 5 additions & 3 deletions scripts/e2e.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ function Invoke-Test {
node "$gmCommand" compile @compileArgs
if ($LASTEXITCODE -ne 0) { throw "compile (cold) failed" }

Write-Output "--- compile (warm) ---"
node "$gmCommand" compile @compileArgs
if ($LASTEXITCODE -ne 0) { throw "compile (warm) failed" }
# run again with a warm cache, this time with package
# FIXME: the package command seems to be broken on windows! We need to fix this
#Write-Output "--- package ---"
#node "$gmCommand" package @compileArgs
#if ($LASTEXITCODE -ne 0) { throw "package failed" }

Write-Output "--- resourcetool ---"
node "$gmCommand" resourcetool eval "resource list" --cache-dir "$gmCacheDir"
Expand Down
21 changes: 16 additions & 5 deletions scripts/e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,35 @@ GM_CACHE_DIR="$(pwd)/.gmcache"

run_test() {
local template="$1"
local target="$2"
local target="${2:-}"
local toolchain="${3:-}"

echo "=== E2E: template='$template' target='$target' toolchain='${toolchain:-default}' ==="
echo "=== E2E: template='$template' target='${target:-default}' toolchain='${toolchain:-default}' ==="

rm -rf test-game
node "$GM_COMMAND" init --template "$template" --name="test-game" --no-interactive --cache-dir "$GM_CACHE_DIR"
cd test-game

local compile_args=(--target "$target" --cache-dir "$GM_CACHE_DIR")
local compile_args=(--cache-dir "$GM_CACHE_DIR")
if [ -n "$target" ]; then
compile_args+=(--target "$target")
fi
if [ -n "$toolchain" ]; then
compile_args+=(--toolchain "$toolchain")
fi

echo "--- compile (cold) ---"
node "$GM_COMMAND" compile "${compile_args[@]}"

echo "--- compile (warm) ---"
node "$GM_COMMAND" compile "${compile_args[@]}"
# Run again with a warm cache and the package command
# unless we are on a mac runner since it looks like we need a signing key for the game
if [ "$(uname)" != "Darwin" ]; then
echo "--- package ---"
node "$GM_COMMAND" package "${compile_args[@]}"
else
echo "--- compile ---"
node "$GM_COMMAND" compile "${compile_args[@]}"
fi

echo "--- resourcetool ---"
node "$GM_COMMAND" resourcetool eval "resource list" --cache-dir "$GM_CACHE_DIR"
Expand All @@ -36,6 +46,7 @@ run_test() {
export NO_COLOR=1

run_test "Blank Game" operagx
run_test "Blank Game"

#run_test "Blank Game" operagx gmrt

Expand Down
15 changes: 15 additions & 0 deletions src/gm-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,21 @@ export const gms2Schema = z
.describe("Path to the Emscripten SDK used when building with YYC"),
})
.partial(),
windows: z
.object({
packageType: z.enum(["zip", "nsis"]),
})
.partial(),
mac: z
.object({
packageType: z.enum(["zip", "dmg"]),
})
.partial(),
linux: z
.object({
packageType: z.enum(["zip", "appimage"]),
})
.partial(),
})
.partial();

Expand Down
18 changes: 18 additions & 0 deletions src/gms2/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,30 @@ export interface Gms2ToolchainOptions {
packageType?: "zip" | "wallpaper" | "gamestrip";
emscriptenSdk?: string;
};
windows: {
packageType?: "zip" | "nsis";
};
mac: {
packageType?: "zip" | "dmg";
};
linux: {
packageType?: "zip" | "appimage";
};
}

export function defaultGms2ToolchainOptions(): Gms2ToolchainOptions {
return {
operagx: {
packageType: "zip",
},
windows: {
packageType: "zip",
},
mac: {
packageType: "zip",
},
linux: {
packageType: "zip",
},
};
}
144 changes: 88 additions & 56 deletions src/gms2/use-gms2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ export async function useGms2(
const defaults = defaultGms2ToolchainOptions();
const toolchainOptions: Gms2ToolchainOptions = {
operagx: options.toolchainOptions.operagx ?? defaults.operagx,
windows: options.toolchainOptions.windows ?? defaults.windows,
mac: options.toolchainOptions.mac ?? defaults.mac,
linux: options.toolchainOptions.linux ?? defaults.linux,
};

if (runtime === "YYC" && options.target === "windows") {
Expand Down Expand Up @@ -106,27 +109,24 @@ export async function useGms2(
successMessage = "Game exited";
} else {
label = `Packaging for ${options.target}`;
let targetFile: string;
if (command.outputPath === undefined) {
const ext = packageExtension(options.target);
const projectDir = ctx.path.dirname(options.projectPath);
const projectName = getProjectName(ctx, options.projectPath);
targetFile = ctx.path.join(projectDir, `${projectName}${ext ?? ""}`);
} else {
const projectDir = ctx.path.dirname(options.projectPath);
targetFile = ctx.path.resolve(projectDir, command.outputPath);
}
igorAction = getPackageAction(options.target);
extraArgs = [
"-tf",
const projectDir = ctx.path.dirname(options.projectPath);
const projectName = getProjectName(ctx, options.projectPath);
const resolvedOutputPath =
command.outputPath !== undefined
? ctx.path.resolve(projectDir, command.outputPath)
: undefined;
const {
action,
targetFile,
...(options.target === "operagx"
? [
"-packagetype",
gxPackageTypeArg(toolchainOptions.operagx.packageType),
]
: []),
];
extraArgs: packageArgs,
} = getPackageAction(
options.target,
toolchainOptions,
resolvedOutputPath,
ctx.path.join(projectDir, projectName),
);
igorAction = action;
extraArgs = ["-tf", targetFile, ...packageArgs];
successMessage = `Package created: ${targetFile}`;
}

Expand Down Expand Up @@ -171,44 +171,76 @@ export async function useGms2(
actionLog.success(successMessage);
}

function gxPackageTypeArg(
packageType: Gms2ToolchainOptions["operagx"]["packageType"],
): string {
switch (packageType) {
case undefined:
case "zip":
return "OperaGXPackage_Zip";
case "gamestrip":
return "OperaGXPackage_Gamestrip";
case "wallpaper":
return "OperaGXPackage_Wallpaper";
default:
packageType satisfies never;
throw new Error("Unreachable");
}
}

function getPackageAction(target: Target): string {
function getPackageAction(
target: Target,
options: Gms2ToolchainOptions,
outputPath: string | undefined,
defaultBasePath: string,
): {
action: string;
targetFile: string;
extraArgs: string[];
} {
switch (target) {
case "windows":
case "mac":
case "linux":
return "PackageZip";
default:
return "Package";
// FIXME: exhaustiveness checking and fix for platforms like xbox: PackageSubmissionXboxOne", PackageSubmissionXboxSeriesXS
}
}

function packageExtension(target: Target): string | undefined {
switch (target) {
case "windows":
case "linux":
case "mac":
case "operagx":
return ".zip";
case "windows": {
const nsis = options.windows.packageType === "nsis";
return {
action: nsis ? "PackageNsis" : "PackageZip",
targetFile: outputPath ?? `${defaultBasePath}${nsis ? ".exe" : ".zip"}`,
extraArgs: [],
};
}
case "mac": {
const dmg = options.mac.packageType === "dmg";
return {
action: dmg ? "PackageDMG" : "PackageZip",
targetFile: outputPath ?? `${defaultBasePath}${dmg ? ".dmg" : ".zip"}`,
extraArgs: [],
};
}
case "operagx": {
let packageTypeArg: string;
switch (options.operagx.packageType) {
case undefined:
case "zip":
packageTypeArg = "OperaGXPackage_Zip";
break;
case "gamestrip":
packageTypeArg = "OperaGXPackage_Gamestrip";
break;
case "wallpaper":
packageTypeArg = "OperaGXPackage_Wallpaper";
break;
default:
options.operagx.packageType satisfies never;
throw new Error("Unreachable");
}
return {
action: "Package",
targetFile: outputPath ?? `${defaultBasePath}.zip`,
extraArgs: ["-packagetype", packageTypeArg],
};
}
case "linux": {
const appimage = options.linux.packageType === "appimage";
if (
appimage &&
outputPath !== undefined &&
!outputPath.endsWith(".AppImage")
) {
throw new KnownError(
"When packaging for Linux with AppImage format, the output filename must end in .AppImage.",
);
}
return {
action: "Package",
targetFile:
outputPath ?? `${defaultBasePath}${appimage ? ".AppImage" : ".zip"}`,
extraArgs: [],
};
}
default:
return undefined;
throw new KnownError("Target not supported in GM-CLI yet.");
}
}

Expand Down
Loading