From 2131cc396031cf789f0b8fa220f81ec33a7c3f3c Mon Sep 17 00:00:00 2001 From: charlie-runreal Date: Tue, 13 May 2025 11:03:42 -0500 Subject: [PATCH 1/7] refactor: new and renamed commands to match UShell --- README.md | 17 ++- src/cmd.ts | 24 +-- src/commands/debug/index.ts | 13 -- .../debug-buildId.ts => info/buildId.ts} | 4 +- .../{debug/debug-config.ts => info/config.ts} | 4 +- src/commands/info/index.ts | 15 ++ src/commands/{ => info}/list-targets.ts | 8 +- src/commands/project/build.ts | 58 ++++++++ src/commands/project/clean.ts | 37 ++++- src/commands/project/compile.ts | 35 ----- src/commands/project/cook.ts | 40 ++++- src/commands/project/editor.ts | 32 ---- src/commands/project/index.ts | 12 +- src/commands/project/pkg.ts | 100 ++++++++++--- src/commands/project/run.ts | 26 ---- src/commands/project/runpython.ts | 46 ------ src/commands/run/client.ts | 36 +++++ src/commands/run/commandlet.ts | 52 +++++++ src/commands/run/editor.ts | 36 +++++ src/commands/run/game.ts | 36 +++++ src/commands/run/index.ts | 21 +++ src/commands/run/python.ts | 50 +++++++ src/commands/run/server.ts | 36 +++++ .../{project/gen.ts => sln/generate.ts} | 8 +- src/commands/sln/index.ts | 13 ++ src/commands/sln/open.ts | 30 ++++ src/lib/engine.ts | 102 ++++++++++--- src/lib/project.ts | 138 +++++++++++------- src/lib/types.ts | 2 +- src/lib/utils.ts | 25 ++++ 30 files changed, 756 insertions(+), 300 deletions(-) delete mode 100644 src/commands/debug/index.ts rename src/commands/{debug/debug-buildId.ts => info/buildId.ts} (78%) rename src/commands/{debug/debug-config.ts => info/config.ts} (85%) create mode 100644 src/commands/info/index.ts rename src/commands/{ => info}/list-targets.ts (87%) create mode 100644 src/commands/project/build.ts delete mode 100644 src/commands/project/compile.ts delete mode 100644 src/commands/project/editor.ts delete mode 100644 src/commands/project/run.ts delete mode 100644 src/commands/project/runpython.ts create mode 100644 src/commands/run/client.ts create mode 100644 src/commands/run/commandlet.ts create mode 100644 src/commands/run/editor.ts create mode 100644 src/commands/run/game.ts create mode 100644 src/commands/run/index.ts create mode 100644 src/commands/run/python.ts create mode 100644 src/commands/run/server.ts rename src/commands/{project/gen.ts => sln/generate.ts} (73%) create mode 100644 src/commands/sln/index.ts create mode 100644 src/commands/sln/open.ts diff --git a/README.md b/README.md index 4f40409..4782761 100644 --- a/README.md +++ b/README.md @@ -24,20 +24,23 @@ ## Getting Started ```sh -# Compile the editor -runreal project compile Editor +# Build the editor +runreal project build Editor -# Compile your project targets -runreal project compile Client +# Build your project targets +runreal project build Client # List available build targets -runreal list-targets +runreal info list-targets + +# Run your editor +runreal run Editor # Run your game -runreal project run +runreal run Game # Package your project -runreal project pkg -p Win64 -c Development +runreal project pkg Game Win64 Development nopak # Execute a buildgraph script runreal buildgraph run diff --git a/src/cmd.ts b/src/cmd.ts index cb72fcd..522a28a 100644 --- a/src/cmd.ts +++ b/src/cmd.ts @@ -4,18 +4,19 @@ import { Config } from './lib/config.ts' import { logger, LogLevel } from './lib/logger.ts' import { VERSION } from './version.ts' -import { debug } from './commands/debug/index.ts' +import { buildgraph } from './commands/buildgraph/index.ts' +import { run } from './commands/run/index.ts' import { engine } from './commands/engine/index.ts' +import { info } from './commands/info/index.ts' +import { project } from './commands/project/index.ts' +import { sln } from './commands/sln/index.ts' import { init } from './commands/init.ts' import { uat } from './commands/uat.ts' import { ubt } from './commands/ubt.ts' -import { buildgraph } from './commands/buildgraph/index.ts' import { workflow } from './commands/workflow/index.ts' import { script } from './commands/script.ts' import { uasset } from './commands/uasset/index.ts' import { auth } from './commands/auth.ts' -import { project } from './commands/project/index.ts' -import { listTargets } from './commands/list-targets.ts' const LogLevelType = new EnumType(LogLevel) export const cmd = new Command() @@ -51,15 +52,16 @@ export const cli = cmd .action(function () { this.showHelp() }) - .command('init', init) - .command('debug', debug) - .command('list-targets', listTargets) + .command('buildgraph', buildgraph) + .command('run', run) .command('engine', engine) + .command('project', project) + .command('sln', sln) + .command('uasset', uasset) + .command('workflow', workflow) + .command('info', info) + .command('init', init) .command('uat', uat) .command('ubt', ubt) - .command('buildgraph', buildgraph) - .command('workflow', workflow) .command('script', script) .command('auth', auth) - .command('uasset', uasset) - .command('project', project) diff --git a/src/commands/debug/index.ts b/src/commands/debug/index.ts deleted file mode 100644 index 79ff529..0000000 --- a/src/commands/debug/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Command } from '@cliffy/command' -import type { GlobalOptions } from '../../lib/types.ts' - -import { debugConfig } from './debug-config.ts' -import { debugBuildId } from './debug-buildId.ts' - -export const debug = new Command() - .description('debug') - .action(function () { - this.showHelp() - }) - .command('config', debugConfig) - .command('buildId', debugBuildId) diff --git a/src/commands/debug/debug-buildId.ts b/src/commands/info/buildId.ts similarity index 78% rename from src/commands/debug/debug-buildId.ts rename to src/commands/info/buildId.ts index 4c1337a..2abdefa 100644 --- a/src/commands/debug/debug-buildId.ts +++ b/src/commands/info/buildId.ts @@ -2,11 +2,11 @@ import { Command } from '@cliffy/command' import { Config } from '../../lib/config.ts' import type { GlobalOptions } from '../../lib/types.ts' -export type DebugBuildIdOptions = typeof debugBuildId extends +export type DebugBuildIdOptions = typeof buildId extends Command, [], GlobalOptions> ? Options : never -export const debugBuildId = new Command() +export const buildId = new Command() .description('debug buildId') .action((options) => { const config = Config.getInstance() diff --git a/src/commands/debug/debug-config.ts b/src/commands/info/config.ts similarity index 85% rename from src/commands/debug/debug-config.ts rename to src/commands/info/config.ts index ba04ba6..b662c56 100644 --- a/src/commands/debug/debug-config.ts +++ b/src/commands/info/config.ts @@ -2,11 +2,11 @@ import { Command } from '@cliffy/command' import { Config } from '../../lib/config.ts' import type { GlobalOptions } from '../../lib/types.ts' -export type DebugConfigOptions = typeof debugConfig extends +export type DebugConfigOptions = typeof config extends Command, [], GlobalOptions> ? Options : never -export const debugConfig = new Command() +export const config = new Command() .option('-r, --render', 'Render the config with substitutions') .description('debug config') .action((options) => { diff --git a/src/commands/info/index.ts b/src/commands/info/index.ts new file mode 100644 index 0000000..7adecb5 --- /dev/null +++ b/src/commands/info/index.ts @@ -0,0 +1,15 @@ +import { Command } from '@cliffy/command' +import type { GlobalOptions } from '../../lib/types.ts' + +import { buildId } from './buildId.ts' +import { config } from './config.ts' +import { listTargets } from './list-targets.ts' + +export const info = new Command() + .description('info') + .action(function () { + this.showHelp() + }) + .command('buildId', buildId) + .command('config', config) + .command('list-targets', listTargets) diff --git a/src/commands/list-targets.ts b/src/commands/info/list-targets.ts similarity index 87% rename from src/commands/list-targets.ts rename to src/commands/info/list-targets.ts index 484cdc2..c4dc192 100644 --- a/src/commands/list-targets.ts +++ b/src/commands/info/list-targets.ts @@ -1,8 +1,8 @@ import { Command } from '@cliffy/command' -import { createProject } from '../lib/project.ts' -import { createEngine } from '../lib/engine.ts' -import type { GlobalOptions } from '../lib/types.ts' -import { Config } from '../lib/config.ts' +import { createProject } from '../../lib/project.ts' +import { createEngine } from '../../lib/engine.ts' +import type { GlobalOptions } from '../../lib/types.ts' +import { Config } from '../../lib/config.ts' export type ListTargetsOptions = typeof listTargets extends Command ? Options diff --git a/src/commands/project/build.ts b/src/commands/project/build.ts new file mode 100644 index 0000000..dce1d21 --- /dev/null +++ b/src/commands/project/build.ts @@ -0,0 +1,58 @@ +import { Command, EnumType } from '@cliffy/command' + +import { Engine, EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' +import { createProject } from '../../lib/project.ts' +import type { GlobalOptions } from '../../lib/types.ts' +import { Config } from '../../lib/config.ts' + +export type CompileOptions = typeof build extends Command + ? Options + : never + +export const build = new Command() + .description('Builds a target. Can be Editor, Client, Server, or Game') + .type('Target', new EnumType(EngineTarget)) + .type('Configuration', new EnumType(EngineConfiguration)) + .type('Platform', new EnumType(EnginePlatform)) + .arguments(' [ubtArgs...]') + .option('-p, --platform ', 'Platform to build, defaults to host platform', { + default: Engine.getCurrentPlatform(), + }) + .option('-c, --configuration ', 'Configuration to build, defaults to Development', { + default: EngineConfiguration.Development, + }) + .option('--clean', 'Clean the current build first', { default: false }) + .option('--nouht', 'Skips building UnrealHeaderTool', { default: false }) + .option('--noxge', 'Disables Incredibuild', { default: true }) + .option('--dry-run', 'Dry run', { default: false }) + .stopEarly() + .action(async (options, target = EngineTarget.Editor, ...ubtArgs: Array) => { + const { platform, configuration, dryRun, clean, nouht, noxge } = options as CompileOptions + + const config = Config.getInstance() + const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ + cliOptions: options, + }) + const project = await createProject(enginePath, projectPath) + + if (options.clean) { + const result = await project.compile({ + target: target as EngineTarget, + configuration: configuration as EngineConfiguration, + platform: platform as EnginePlatform, + dryRun: dryRun, + clean: true, + }) + } + + await project.compile({ + target: target as EngineTarget, + configuration: configuration as EngineConfiguration, + platform: platform as EnginePlatform, + dryRun: dryRun, + extraArgs: ubtArgs, + clean: false, + nouht: nouht, + noxge: noxge, + }) + }) diff --git a/src/commands/project/clean.ts b/src/commands/project/clean.ts index 544a293..7d14fd9 100644 --- a/src/commands/project/clean.ts +++ b/src/commands/project/clean.ts @@ -1,15 +1,42 @@ -import { Command } from '@cliffy/command' +import { Command, EnumType } from '@cliffy/command' + +import { Engine, EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' import { createProject } from '../../lib/project.ts' +import type { GlobalOptions } from '../../lib/types.ts' import { Config } from '../../lib/config.ts' -export const clean = new Command() +export type CleanOptions = typeof clean extends Command + ? Options + : never + +export const clean = new Command() + .description('Cleans the output of a target build') + .type('Target', new EnumType(EngineTarget)) + .type('Configuration', new EnumType(EngineConfiguration)) + .type('Platform', new EnumType(EnginePlatform)) + .arguments(' [ubtArgs...]') + .option('-p, --platform ', 'Platform to build, defaults to host platform', { + default: Engine.getCurrentPlatform(), + }) + .option('-c, --configuration ', 'Configuration to build, defaults to Development', { + default: EngineConfiguration.Development, + }) .option('--dry-run', 'Dry run', { default: false }) - .description('clean') - .action(async (options) => { + .stopEarly() + .action(async (options, target = EngineTarget.Editor, ...ubtArgs: Array) => { + const { platform, configuration, dryRun } = options as CleanOptions + const config = Config.getInstance() const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ cliOptions: options, }) const project = await createProject(enginePath, projectPath) - project.runClean(options.dryRun) + + await project.compile({ + target: target as EngineTarget, + configuration: configuration as EngineConfiguration, + platform: platform as EnginePlatform, + dryRun: dryRun, + clean: true, + }) }) diff --git a/src/commands/project/compile.ts b/src/commands/project/compile.ts deleted file mode 100644 index 2643c57..0000000 --- a/src/commands/project/compile.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Command, EnumType, ValidationError } from '@cliffy/command' - -import { Engine, EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' -import { createProject } from '../../lib/project.ts' -import type { GlobalOptions } from '../../lib/types.ts' -import { Config } from '../../lib/config.ts' - -export type CompileOptions = typeof compile extends Command - ? Options - : never - -export const compile = new Command() - .description('Compile a project') - .type('Configuration', new EnumType(EngineConfiguration)) - .type('Platform', new EnumType(EnginePlatform)) - .option('-p, --platform ', 'Platform', { default: Engine.getCurrentPlatform() }) - .option('-c, --configuration ', 'Configuration', { - default: EngineConfiguration.Development, - }) - .option('--dry-run', 'Dry run', { default: false }) - .arguments('') - .action(async (options, target = EngineTarget.Editor) => { - const { platform, configuration, dryRun } = options as CompileOptions - const config = Config.getInstance() - const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ - cliOptions: options, - }) - const project = await createProject(enginePath, projectPath) - await project.compile({ - target: target as EngineTarget, - configuration: configuration as EngineConfiguration, - platform: platform as EnginePlatform, - dryRun: dryRun, - }) - }) diff --git a/src/commands/project/cook.ts b/src/commands/project/cook.ts index beea526..7c88886 100644 --- a/src/commands/project/cook.ts +++ b/src/commands/project/cook.ts @@ -1,25 +1,49 @@ -import { Command } from '@cliffy/command' +import { Command, EnumType } from '@cliffy/command' import { createProject } from '../../lib/project.ts' import type { GlobalOptions } from '../../lib/types.ts' import { Config } from '../../lib/config.ts' +import { CookTarget } from '../../lib/engine.ts' + +export type CookOptions = typeof cook extends Command + ? Options + : never export const cook = new Command() - .description('Cook the project') - .arguments('') + .description('Cook content for the target') + .type('Target', new EnumType(CookTarget)) + .arguments(' [cookArguments...]') + .option('--cultures ', 'Comma separated string of cultures to cook, defaults to all', { + required: false, + }) + .option('--onthefly', 'Launch as an on-the-fly server', { default: false }) + .option('--iterate', 'Cook iteratively', { default: true }) + .option('--noxge', 'Disable XGE shader compilation', { default: true }) + .option('--debug', 'Use debug executables', { default: false }) .option('--dry-run', 'Dry run', { default: false }) - .option('--compile', 'Compile before Cook', { default: false }) .stopEarly() - .action(async (options, ...cookArguments: Array) => { + .action(async (options, target = CookTarget.Windows, ...cookArguments: Array) => { + const { dryRun, noxge, debug, iterate, onthefly, cultures } = options as CookOptions const config = Config.getInstance() const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ cliOptions: options, }) const project = await createProject(enginePath, projectPath) - if (options.compile) { - await project.compile({}) + + let cultureArgs: string[] = [] + if (cultures) { + cultureArgs = cultures.replace(' ', '').split(',') } - await project.cookContent({ extraArgs: cookArguments }) + await project.cookContent({ + target: target as CookTarget, + extraArgs: cookArguments, + cultures: cultureArgs, + onTheFly: onthefly, + iterate: iterate, + noxge: noxge, + debug: debug, + dryRun: dryRun, + }) }) diff --git a/src/commands/project/editor.ts b/src/commands/project/editor.ts deleted file mode 100644 index dc57116..0000000 --- a/src/commands/project/editor.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Command } from '@cliffy/command' - -import { createProject } from '../../lib/project.ts' -import type { GlobalOptions } from '../../lib/types.ts' -import { Config } from '../../lib/config.ts' - -export const editor = new Command() - .description('Run the editor') - .arguments('') - .option('--dry-run', 'Dry run', { default: false }) - .option('--compile', 'Compile binaries first', { default: false }) - .stopEarly() - .action(async (options, ...editorArguments: Array) => { - const config = Config.getInstance() - const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ - cliOptions: options, - }) - const project = await createProject(enginePath, projectPath) - - if (options.dryRun) { - console.log(`Would open editor with ${editorArguments}`) - Deno.exit() - } - - console.log(`Running editor with ${editorArguments}`) - - if (options.compile) { - await project.compileAndRunEditor({ extraRunArgs: editorArguments }) - } else { - await project.runEditor({ extraArgs: editorArguments }) - } - }) diff --git a/src/commands/project/index.ts b/src/commands/project/index.ts index 81708d9..3087ada 100644 --- a/src/commands/project/index.ts +++ b/src/commands/project/index.ts @@ -2,25 +2,17 @@ import { Command } from '@cliffy/command' import type { GlobalOptions } from '../../lib/types.ts' +import { build } from './build.ts' import { clean } from './clean.ts' -import { compile } from './compile.ts' import { cook } from './cook.ts' -import { editor } from './editor.ts' -import { gen } from './gen.ts' import { pkg } from './pkg.ts' -import { run } from './run.ts' -import { runpython } from './runpython.ts' export const project = new Command() .description('project') .action(function () { this.showHelp() }) + .command('build', build) .command('clean', clean) - .command('compile', compile) .command('cook', cook) - .command('editor', editor) - .command('gen', gen) .command('pkg', pkg) - .command('run', run) - .command('runpython', runpython) diff --git a/src/commands/project/pkg.ts b/src/commands/project/pkg.ts index 46c0e6e..782d9ad 100644 --- a/src/commands/project/pkg.ts +++ b/src/commands/project/pkg.ts @@ -1,36 +1,96 @@ import { Command, EnumType } from '@cliffy/command' -import { Engine, EngineConfiguration, EnginePlatform } from '../../lib/engine.ts' import { Config } from '../../lib/config.ts' -import type { GlobalOptions } from '../../lib/types.ts' import { createProject } from '../../lib/project.ts' +import type { GlobalOptions } from '../../lib/types.ts' +import { + CookStyle, + CookTarget, + EngineConfiguration, + EnginePlatform, + EngineTarget, + GameTarget, + getPlatformCookTarget, +} from '../../lib/engine.ts' export type PkgOptions = typeof pkg extends Command ? Options : never -export const pkg = new Command() - .description('package') +export const pkg = new Command() + .description('Package a project') + .type('Style', new EnumType(CookStyle)) + .type('Target', new EnumType(GameTarget)) .type('Configuration', new EnumType(EngineConfiguration)) .type('Platform', new EnumType(EnginePlatform)) - .arguments('') - .option('-p, --platform ', 'Platform', { default: Engine.getCurrentPlatform() }) - .option('-c, --configuration ', 'Configuration', { - default: EngineConfiguration.Development, - }) - .option('-a, --archive-directory ', 'Path to archive directory') + .arguments(' [uatArgs...]') + .option('--dry-run', 'Dry run', { default: false }) .option('-z, --zip', 'Should we zip the archive') - .option('-d, --dry-run', 'Dry run') - .option('--compile', 'Use the precompiled binaries', { default: false }) - .option('--profile ', 'Build profile', { default: 'client', required: true }) + .option( + '--buildargs ', + 'Build code prior to staging, comma separated list of arguments for the build', + ) + .option( + '--cookargs ', + 'Cook content prior to staging, comma separated list of arguments for the cook', + ) + .option('-a, --archive-directory ', 'Path to archive directory') .stopEarly() - .action(async (options, ...pkgArguments: Array) => { - const { platform, configuration, dryRun, profile, archiveDirectory, zip } = options as PkgOptions - const cfg = Config.getInstance() - const { engine: { path: enginePath }, project: { path: projectPath } } = cfg.mergeConfigCLIConfig({ + .action(async (options, target, platform, configuration, style, ...uatArgs: Array) => { + const { dryRun, zip, buildargs, cookargs, archiveDirectory } = options as PkgOptions + + const config = Config.getInstance() + const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ cliOptions: options, }) + const project = await createProject(enginePath, projectPath) - const args = pkg.getLiteralArgs().concat(pkgArguments) + const args = uatArgs - const project = await createProject(enginePath, projectPath) - project.package({ archiveDirectory: archiveDirectory, profile: profile, extraArgs: args }) + switch (style) { + case CookStyle.pak: + args.push('-pak') + break + case CookStyle.zen: + args.push('-zen') + break + case CookStyle.nopak: + args.push('-nopak') + break + } + + console.log(`${buildargs}`) + if (buildargs) { + console.log(`Recieved build arguments - ${buildargs}`) + project.compile({ + target: target as GameTarget, + configuration: configuration as EngineConfiguration, + platform: platform as EnginePlatform, + dryRun: dryRun, + extraArgs: (buildargs as string).split(','), + }) + args.push('-skipbuild') + } else { + args.push('-build') + } + if (cookargs) { + console.log(`Recieved cook arguments - ${cookargs}`) + const cookTarget = getPlatformCookTarget(platform, target) + project.cookContent({ + target: cookTarget as CookTarget, + dryRun: dryRun, + extraArgs: cookargs, + }) + args.push('-skipcook') + } else { + args.push('-cook') + } + + project.package({ + profile: target, + configuration: configuration, + extraArgs: args, + dryRun: dryRun, + platform: platform, + zip: zip, + archiveDirectory: archiveDirectory, + }) }) diff --git a/src/commands/project/run.ts b/src/commands/project/run.ts deleted file mode 100644 index 9ebdf95..0000000 --- a/src/commands/project/run.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Command } from '@cliffy/command' - -import { createProject } from '../../lib/project.ts' -import type { GlobalOptions } from '../../lib/types.ts' -import { Config } from '../../lib/config.ts' - -export const run = new Command() - .description('Run the game') - .arguments('') - .option('--dry-run', 'Dry run', { default: false }) - .option('--compile', 'Use the precompiled binaries', { default: false }) - .stopEarly() - .action(async (options, ...runArguments: Array) => { - const config = Config.getInstance() - const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ - cliOptions: options, - }) - - const project = await createProject(enginePath, projectPath) - - if (options.compile) { - await project.runEditor({ extraArgs: ['-game', ...runArguments] }) - } else { - await project.compileAndRunEditor({ extraRunArgs: ['-game', ...runArguments] }) - } - }) diff --git a/src/commands/project/runpython.ts b/src/commands/project/runpython.ts deleted file mode 100644 index c1d70ca..0000000 --- a/src/commands/project/runpython.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Command } from '@cliffy/command' -import * as path from '@std/path' -import { Config } from '../../lib/config.ts' -import type { GlobalOptions } from '../../lib/types.ts' -import { createProject } from '../../lib/project.ts' - -export type RunPythonOptions = typeof runpython extends - Command ? Options - : never - -export const runpython = new Command() - .description('Run Python script in Unreal Engine headless mode') - .option('-s, --script ', 'Path to Python script', { required: true }) - .option('--stdout', 'Redirect output to stdout', { default: true }) - .option('--nosplash', 'Skip splash screen', { default: true }) - .option('--nopause', "Don't pause after execution", { default: true }) - .option('--nosound', 'Disable sound', { default: true }) - .option('--args ', 'Additional arguments to pass to the script') - .action(async (options) => { - const config = Config.getInstance() - const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ - cliOptions: options, - }) - const project = await createProject(enginePath, projectPath) - - // Resolve absolute path to script - const scriptPath = path.resolve(options.script) - - // Build command arguments - const args = [ - '-unattended', - ] - - // Add optional flags - if (options.stdout) args.push('-stdout') - if (options.nosplash) args.push('-nosplash') - if (options.nopause) args.push('-nopause') - if (options.nosound) args.push('-nosound') - - // Add any additional arguments - if (options.args) { - args.push(options.args) - } - - project.runPython(scriptPath, args) - }) diff --git a/src/commands/run/client.ts b/src/commands/run/client.ts new file mode 100644 index 0000000..2b8b6b4 --- /dev/null +++ b/src/commands/run/client.ts @@ -0,0 +1,36 @@ +import { Command } from '@cliffy/command' + +import { createProject } from '../../lib/project.ts' +import type { GlobalOptions } from '../../lib/types.ts' +import { Config } from '../../lib/config.ts' +import { EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' + +export type ClientOptions = typeof client extends Command + ? Options + : never + +export const client = new Command() + .description('Launches the game client') + .arguments(' [runArguments...]>') + .option('--dry-run', 'Dry run', { default: false }) + .option('--compile', 'Build the target prior to running it', { default: false }) + .stopEarly() + .action(async (options, configuration = EngineConfiguration.Development, ...runArguments: Array) => { + const { dryRun, compile } = options as ClientOptions + const config = Config.getInstance() + const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ + cliOptions: options, + }) + + const project = await createProject(enginePath, projectPath) + + if (compile) { + await project.compile({ + target: EngineTarget.Client, + configuration: configuration as EngineConfiguration, + dryRun: options.dryRun, + }) + } + + await project.runEditor({ extraArgs: ['-client', ...runArguments] }) + }) diff --git a/src/commands/run/commandlet.ts b/src/commands/run/commandlet.ts new file mode 100644 index 0000000..8e33f8b --- /dev/null +++ b/src/commands/run/commandlet.ts @@ -0,0 +1,52 @@ +import { Command } from '@cliffy/command' + +import { createProject } from '../../lib/project.ts' +import type { GlobalOptions } from '../../lib/types.ts' +import { Config } from '../../lib/config.ts' +import { EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' + +export type CommandletOptions = typeof commandlet extends + Command ? Options + : never + +export const commandlet = new Command() + .description('Run commandlet Unreal Engine headless mode') + .arguments(' [runArguments...]') + .option('--dry-run', 'Dry run', { default: false }) + .option('--compile', 'Build the target prior to running it', { default: false }) + .stopEarly() + .action( + async ( + options, + configuration = EngineConfiguration.Development, + commandletName, + ...runArguments: Array + ) => { + const { dryRun, compile } = options as CommandletOptions + const config = Config.getInstance() + const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ + cliOptions: options, + }) + + const project = await createProject(enginePath, projectPath) + + if (compile) { + await project.compile({ + target: EngineTarget.Editor, + configuration: configuration as EngineConfiguration, + dryRun: options.dryRun, + }) + } + + const args = [ + `-run=${commandletName}`, + '-stdout', + '-nosplash', + '-nopause', + '-nosound', + ...runArguments, + ] + + await project.runEditor({ extraArgs: args, useCmd: true }) + }, + ) diff --git a/src/commands/run/editor.ts b/src/commands/run/editor.ts new file mode 100644 index 0000000..6cd3c39 --- /dev/null +++ b/src/commands/run/editor.ts @@ -0,0 +1,36 @@ +import { Command } from '@cliffy/command' + +import { createProject } from '../../lib/project.ts' +import type { GlobalOptions } from '../../lib/types.ts' +import { Config } from '../../lib/config.ts' +import { EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' + +export type EditorOptions = typeof editor extends Command + ? Options + : never + +export const editor = new Command() + .description('Run the game') + .arguments(' [runArguments...]>') + .option('--dry-run', 'Dry run', { default: false }) + .option('--compile', 'Build the target prior to running it', { default: false }) + .stopEarly() + .action(async (options, configuration = EngineConfiguration.Development, ...runArguments: Array) => { + const { dryRun, compile } = options as EditorOptions + const config = Config.getInstance() + const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ + cliOptions: options, + }) + + const project = await createProject(enginePath, projectPath) + + if (compile) { + await project.compile({ + target: EngineTarget.Editor, + configuration: configuration as EngineConfiguration, + dryRun: options.dryRun, + }) + } + + await project.runEditor({ extraArgs: [...runArguments] }) + }) diff --git a/src/commands/run/game.ts b/src/commands/run/game.ts new file mode 100644 index 0000000..7fdfe71 --- /dev/null +++ b/src/commands/run/game.ts @@ -0,0 +1,36 @@ +import { Command } from '@cliffy/command' + +import { createProject } from '../../lib/project.ts' +import type { GlobalOptions } from '../../lib/types.ts' +import { Config } from '../../lib/config.ts' +import { EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' + +export type GameOptions = typeof game extends Command + ? Options + : never + +export const game = new Command() + .description('Launches the game') + .arguments(' [runArguments...]') + .option('--dry-run', 'Dry run', { default: false }) + .option('--compile', 'Build the target prior to running it', { default: false }) + .stopEarly() + .action(async (options, configuration = EngineConfiguration.Development, ...runArguments: Array) => { + const { dryRun, compile } = options as GameOptions + const config = Config.getInstance() + const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ + cliOptions: options, + }) + + const project = await createProject(enginePath, projectPath) + + if (compile) { + await project.compile({ + target: EngineTarget.Game, + configuration: configuration as EngineConfiguration, + dryRun: options.dryRun, + }) + } + + await project.runEditor({ extraArgs: ['-game', ...runArguments] }) + }) diff --git a/src/commands/run/index.ts b/src/commands/run/index.ts new file mode 100644 index 0000000..1691ac5 --- /dev/null +++ b/src/commands/run/index.ts @@ -0,0 +1,21 @@ +import { Command } from '@cliffy/command' +import type { GlobalOptions } from '../../lib/types.ts' + +import { client } from './client.ts' +import { commandlet } from './commandlet.ts' +import { editor } from './editor.ts' +import { game } from './game.ts' +import { python } from './python.ts' +import { server } from './server.ts' + +export const run = new Command() + .description('Run the game, editor, or commandlet') + .action(function () { + this.showHelp() + }) + .command('client', client) + .command('commandlet', commandlet) + .command('editor', editor) + .command('game', game) + .command('python', python) + .command('server', server) diff --git a/src/commands/run/python.ts b/src/commands/run/python.ts new file mode 100644 index 0000000..3642964 --- /dev/null +++ b/src/commands/run/python.ts @@ -0,0 +1,50 @@ +import { Command } from '@cliffy/command' + +import { createProject } from '../../lib/project.ts' +import type { GlobalOptions } from '../../lib/types.ts' +import { Config } from '../../lib/config.ts' +import { EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' + +export type PythonOptions = typeof python extends Command + ? Options + : never + +export const python = new Command() + .description('Run Python script in Unreal Engine headless mode') + .arguments(' [runArguments...]') + .option('--dry-run', 'Dry run', { default: false }) + .option('--compile', 'Build the target prior to running it', { default: false }) + .stopEarly() + .action( + async (options, configuration = EngineConfiguration.Development, scriptPath, ...runArguments: Array) => { + const { dryRun, compile } = options as PythonOptions + const config = Config.getInstance() + const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ + cliOptions: options, + }) + + const project = await createProject(enginePath, projectPath) + + if (compile) { + await project.compile({ + target: EngineTarget.Editor, + configuration: configuration as EngineConfiguration, + dryRun: options.dryRun, + }) + } + + const args = [ + '-run=pythonscript', + `-script=${scriptPath}`, + '-stdout', + '-nosplash', + '-nopause', + '-nosound', + ...runArguments, + ] + + console.log(`Running Python script: ${scriptPath}`) + + await project.runEditor({ extraArgs: args, useCmd: true }) + }, + ) diff --git a/src/commands/run/server.ts b/src/commands/run/server.ts new file mode 100644 index 0000000..425b711 --- /dev/null +++ b/src/commands/run/server.ts @@ -0,0 +1,36 @@ +import { Command } from '@cliffy/command' + +import { createProject } from '../../lib/project.ts' +import type { GlobalOptions } from '../../lib/types.ts' +import { Config } from '../../lib/config.ts' +import { EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' + +export type ServerOptions = typeof server extends Command + ? Options + : never + +export const server = new Command() + .description('Launches the game server') + .arguments(' [runArguments...]') + .option('--dry-run', 'Dry run', { default: false }) + .option('--compile', 'Build the target prior to running it', { default: false }) + .stopEarly() + .action(async (options, configuration = EngineConfiguration.Development, ...runArguments: Array) => { + const { dryRun, compile } = options as ServerOptions + const config = Config.getInstance() + const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ + cliOptions: options, + }) + + const project = await createProject(enginePath, projectPath) + + if (compile) { + await project.compile({ + target: EngineTarget.Server, + configuration: configuration as EngineConfiguration, + dryRun: options.dryRun, + }) + } + + await project.runEditor({ extraArgs: ['-server', ...runArguments] }) + }) diff --git a/src/commands/project/gen.ts b/src/commands/sln/generate.ts similarity index 73% rename from src/commands/project/gen.ts rename to src/commands/sln/generate.ts index 4dbd13a..6254e8a 100644 --- a/src/commands/project/gen.ts +++ b/src/commands/sln/generate.ts @@ -2,13 +2,13 @@ import { Command } from '@cliffy/command' import { Config } from '../../lib/config.ts' import { createProject } from '../../lib/project.ts' -export type GenOptions = typeof gen extends Command, [], void> - ? Options +export type GenOptions = typeof generate extends + Command, [], void> ? Options : never -export const gen = new Command() +export const generate = new Command() .description('generate') - .arguments('') + .arguments('[genArguments...]') .option('--dry-run', 'Dry run', { default: false }) .stopEarly() .action(async (options, ...genArguments: Array) => { diff --git a/src/commands/sln/index.ts b/src/commands/sln/index.ts new file mode 100644 index 0000000..7f4e985 --- /dev/null +++ b/src/commands/sln/index.ts @@ -0,0 +1,13 @@ +import { Command } from '@cliffy/command' +import type { GlobalOptions } from '../../lib/types.ts' + +import { generate } from './generate.ts' +import { open } from './open.ts' + +export const sln = new Command() + .description('debug') + .action(function () { + this.showHelp() + }) + .command('generate', generate) + .command('open', open) diff --git a/src/commands/sln/open.ts b/src/commands/sln/open.ts new file mode 100644 index 0000000..22ce04a --- /dev/null +++ b/src/commands/sln/open.ts @@ -0,0 +1,30 @@ +import { Command } from '@cliffy/command' +import { Config } from '../../lib/config.ts' +import { createProject } from '../../lib/project.ts' +import * as path from '@std/path' +import { exec, findFilesByExtension } from '../../lib/utils.ts' + +export const open = new Command() + .description('open') + .option('--dry-run', 'Dry run', { default: false }) + .action(async (options) => { + const config = Config.getInstance() + const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ + cliOptions: options, + }) + const project = await createProject(enginePath, projectPath) + + const projectSlnFiles = await findFilesByExtension( + path.join(`${project.projectFileVars.projectDir}`, '..'), + 'sln', + false, + ) + const engineSlnFiles = await findFilesByExtension(enginePath, 'sln', false) + + const slnFiles = [...projectSlnFiles, ...engineSlnFiles] + + if (slnFiles.length > 0) { + console.log(`opening ${slnFiles[0]}`) + await exec('cmd.exe', ['cmd.exe', '/c', slnFiles[0]]) + } + }) diff --git a/src/lib/engine.ts b/src/lib/engine.ts index bc050e2..2693f7f 100644 --- a/src/lib/engine.ts +++ b/src/lib/engine.ts @@ -24,6 +24,42 @@ interface EngineVersionData { "BranchName": "++UE5+Release-5.0" } */ + +export enum CookStyle { + pak = 'pak', + zen = 'zen', + nopak = 'nopak', +} + +export enum CookTarget { + Windows = 'Windows', + WindowsClient = 'WindowsClient', + WindowsNoEditor = 'WindowsNoEditor', + WindowsServer = 'WindowsServer', + Linux = 'Linux', + LinuxClient = 'LinuxClient', + LinuxNoEditor = 'LinuxNoEditor', + LinuxServer = 'LinuxServer', + Mac = 'Mac', + MacClient = 'MacClient', + MacNoEditor = 'MacNoEditor', + MacServer = 'MacServer', + Android = 'Android', + Android_ASTC = 'Android_ASTC', + Android_DXT = 'Android_DXT', + Android_ETC2 = 'Android_ETC2', + IOS = 'IOS', + PS4 = 'PS4', + PS5 = 'PS5', + Switch = 'Switch', + XboxOne = 'XboxOne', + XSX = 'XSX', + TVOS = 'TVOS', + HoloLens = 'HoloLens', + AllDesktop = 'AllDesktop', + HTML5 = 'HTML5', +} + export enum EngineConfiguration { Debug = 'Debug', DebugGame = 'DebugGame', @@ -39,8 +75,7 @@ export enum EngineTarget { Server = 'Server', } -export enum ProjectTarget { - Editor = 'Editor', +export enum GameTarget { Game = 'Game', Client = 'Client', Server = 'Server', @@ -76,7 +111,7 @@ export interface TargetInfo { } interface UBTOptions { - target: ProjectTarget | string + target: EngineTarget | string configuration?: EngineConfiguration platform?: EnginePlatform extraArgs?: string[] @@ -108,7 +143,7 @@ export abstract class Engine { abstract getGenerateScript(): string abstract getGitDependencesBin(): string abstract parseEngineTargets(): Promise - abstract getEditorBin(): string + abstract getEditorBin(cmdBin?: boolean, debug?: boolean): string abstract getEditorCmdBin(): string getEngineVersionData(): EngineVersionData { @@ -167,6 +202,34 @@ export abstract class Engine { return await exec(buildScript, args) } + async runEditor({ + useCmd = false, + dryRun = false, + debug = false, + args, + }: { + useCmd?: boolean + dryRun?: boolean + debug?: boolean + args: Array + }) { + const editorBin = this.getEditorBin(useCmd, debug) + + console.log(`Running editor with: ${editorBin} ${args.join(' ')}`) + + if (dryRun) { + return + } + + try { + const result = await exec(editorBin, args) + return result + } catch (error: unknown) { + console.log(`Error running Editor: ${error instanceof Error ? error.message : String(error)}`) + Deno.exit(1) + } + } + async ubt(args: string[] = [], options = { quiet: false }) { const buildScript = this.getBuildScript() return await exec(buildScript, args, options) @@ -238,13 +301,20 @@ class WindowsEngine extends Engine { return [] } } - override getEditorBin(): string { + override getEditorBin(cmdBin?: boolean, debug?: boolean): string { + let exeName = 'UnrealEditor' + if (cmdBin) { + exeName = exeName + '-Cmd' + } + if (debug) { + exeName = exeName + 'Win64-Debug' + } const editorPath = path.join( this.enginePath, 'Engine', 'Binaries', 'Win64', - 'UnrealEditor.exe', + `${exeName}.exe`, ) return editorPath } @@ -321,7 +391,7 @@ class MacosEngine extends Engine { return [] } } - override getEditorBin(): string { + override getEditorBin(cmdBin?: boolean, debug?: boolean): string { const editorPath = path.join( this.enginePath, 'Engine', @@ -404,7 +474,7 @@ class LinuxEngine extends Engine { return [] } } - override getEditorBin(): string { + override getEditorBin(cmdBin?: boolean, debug?: boolean): string { const editorPath = path.join( this.enginePath, 'Engine', @@ -477,15 +547,11 @@ export function getEditorPath(enginePath: string, platform: EnginePlatform): str /** * Get the platform-specific cook target */ -export function getPlatformCookTarget(platform: EnginePlatform): string { - switch (platform) { - case EnginePlatform.Windows: - return 'Windows' - case EnginePlatform.Mac: - return 'MAC' - case EnginePlatform.Linux: - return 'Linux' - default: - throw new Error(`Unsupported platform: ${platform}`) +export function getPlatformCookTarget(platform: EnginePlatform, gameTarget: GameTarget): string { + const prefix = platform + let suffix = gameTarget as string + if (gameTarget == GameTarget.Game) { + suffix = '' } + return prefix + suffix } diff --git a/src/lib/project.ts b/src/lib/project.ts index 93bd0a9..889c273 100644 --- a/src/lib/project.ts +++ b/src/lib/project.ts @@ -4,12 +4,13 @@ import { ValidationError } from '@cliffy/command' import { logger } from '../lib/logger.ts' import { + CookTarget, createEngine, Engine, EngineConfiguration, EnginePlatform, EngineTarget, - getPlatformCookTarget, + GameTarget, TargetInfo, } from '../lib/engine.ts' import { copyBuildGraphScripts, exec, findProjectFile } from '../lib/utils.ts' @@ -21,13 +22,10 @@ Valid Targets: ${targets.join(', ')} } const defaultBCRArgs = [ - '-build', - '-cook', '-stage', '-package', '-prereqs', '-manifests', - '-pak', '-compressed', '-nop4', '-utf8output', @@ -91,26 +89,42 @@ export class Project { extraArgs = [], dryRun = false, platform = this.engine.getPlatformName(), + clean = false, + nouht = false, + noxge = true, }: { - target?: EngineTarget + target?: EngineTarget | GameTarget configuration?: EngineConfiguration platform?: EnginePlatform extraArgs?: string[] dryRun?: boolean + clean?: boolean + nouht?: boolean + noxge?: boolean }) { const args = [ this.projectFileVars.projectArgument, '-NoUBTMakefiles', - '-NoXGE', '-NoHotReload', '-NoCodeSign', '-NoP4', '-TraceWrites', - ].concat(extraArgs) + '-Progress', + ...extraArgs, + ] - const projectTarget = `${this.projectFileVars.projectName}${target}` + if (noxge) { + args.push('-NoXGE') + } + if (clean) { + args.push('-Clean') + } + if (nouht) { + args.push('-NoBuildUHT') + } + + const projectTarget = await this.getProjectTarget(target) - await this.checkTarget(projectTarget) await this.engine.runUBT({ target: projectTarget, configuration: configuration, @@ -120,6 +134,15 @@ export class Project { }) } + async getProjectTarget(target: EngineTarget | GameTarget): Promise { + let projectTarget = `${this.projectFileVars.projectName}` + if (target != EngineTarget.Game) { + projectTarget = projectTarget + `${target}` + } + await this.checkTarget(projectTarget) + return projectTarget + } + async package({ configuration = EngineConfiguration.Development, extraArgs = [], @@ -138,7 +161,7 @@ export class Project { dryRun?: boolean }) { const profileArgs = profiles[profile as keyof typeof profiles] || [] - const bcrArgs = Array.from(new Set([...profileArgs, ...extraArgs])) + const bcrArgs = Array.from(new Set([...profileArgs, ...extraArgs, ...defaultBCRArgs])) bcrArgs.push(this.projectFileVars.projectArgument) bcrArgs.push(`-platform=${platform}`) @@ -183,59 +206,72 @@ export class Project { } } - async compileAndRunEditor({ - extraCompileArgs = [], - extraRunArgs = [], - }: { - extraCompileArgs?: string[] - extraRunArgs?: string[] - }) { - await this.compile({ extraArgs: extraCompileArgs }) - await this.runEditor({ extraArgs: extraRunArgs }) - } - async runEditor({ - extraArgs = [], + useCmd = false, + dryRun = false, + debug = false, + extraArgs, }: { - extraArgs?: string[] + useCmd?: boolean + dryRun?: boolean + debug?: boolean + extraArgs: Array }) { - const args = [ - this.projectFileVars.projectFullPath, - ].concat(extraArgs) - - console.log(`Running editor with: ${this.engine.getEditorBin} ${args.join(' ')}`) - - try { - const result = await exec(this.engine.getEditorBin(), args) - return result - } catch (error: unknown) { - console.log(`Error running Editor: ${error instanceof Error ? error.message : String(error)}`) - Deno.exit(1) - } + await this.engine.runEditor({ + useCmd: useCmd, + dryRun: dryRun, + debug: debug, + args: [this.projectFileVars.projectFullPath, ...extraArgs], + }) } async cookContent({ + target, + cultures, + onTheFly = false, + iterate = true, + noxge = true, + debug = false, + dryRun = false, extraArgs = [], }: { + target: CookTarget extraArgs?: string[] + cultures?: Array + onTheFly?: boolean + iterate?: boolean + noxge?: boolean + dryRun?: boolean + debug?: boolean }) { - const platformTarget = getPlatformCookTarget(this.engine.getPlatformName()) const args = [ this.projectFileVars.projectFullPath, '-run=Cook', - `-targetplatform=${platformTarget}`, + `-targetplatform=${target}`, '-fileopenlog', - ].concat(extraArgs) + '-unversioned', + '-stdout', + ...extraArgs, + ] - console.log(`Running editor with: ${this.engine.getEditorCmdBin} ${args.join(' ')}`) + if (cultures && cultures.length > 0) { + const cultureArg: string = cultures.join('+') + args.push(`-cookcultures=${cultureArg}`) + } - try { - const result = await exec(this.engine.getEditorCmdBin(), args) - return result - } catch (error: unknown) { - console.log(`Error running Editor: ${error instanceof Error ? error.message : String(error)}`) - Deno.exit(1) + if (onTheFly) { + args.push('-cookonthefly') } + + if (iterate) { + args.push('-iterate') + } + + if (noxge) { + args.push('noxge') + } + + await this.engine.runEditor({ useCmd: true, dryRun: dryRun, debug: debug, args: args }) } async parseProjectTargets(): Promise { @@ -284,16 +320,6 @@ export class Project { } } - async runPython(scriptPath: string, extraArgs: Array) { - const args = [ - '-run=pythonscript', - `-script=${scriptPath}`, - ...extraArgs, - ] - logger.info(`Running Python script: ${scriptPath}`) - await this.runEditor({ extraArgs: args }) - } - async runBuildGraph(buildGraphScript: string, args: string[] = []) { let bgScriptPath = path.resolve(buildGraphScript) if (!bgScriptPath.endsWith('.xml')) { diff --git a/src/lib/types.ts b/src/lib/types.ts index 96cdf78..603a1ab 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -4,7 +4,7 @@ import type { $ } from '@david/dax' import type { z } from 'zod' import type { cmd } from '../cmd.ts' -import type { DebugConfigOptions } from '../commands/debug/debug-config.ts' +import type { DebugConfigOptions } from '../commands/info/config.ts' import type { SetupOptions } from '../commands/engine/setup.ts' import type { InstallOptions } from '../commands/engine/install.ts' import type { UpdateOptions } from '../commands/engine/update.ts' diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 20d91f4..3de61a0 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -410,3 +410,28 @@ ${blueprint} ` return html } + +export async function findFilesByExtension( + rootDir: string, + extension: string, + recursive: boolean, +): Promise { + const files: string[] = [] + + try { + for await (const entry of Deno.readDir(rootDir)) { + const checkPath = `${rootDir}/${entry.name}` + + if (entry.isDirectory && recursive) { + const subFiles = await findFilesByExtension(checkPath, extension, recursive) + files.push(...subFiles) + } else if (entry.isFile && checkPath.endsWith(extension)) { + files.push(checkPath) + } + } + } catch (error) { + console.error(`Error reading directory ${rootDir}:`, error) + } + + return files +} From 2a9166a72bfc16c4639ca248449a6f2d5c64db73 Mon Sep 17 00:00:00 2001 From: charlie-runreal Date: Tue, 13 May 2025 20:13:51 -0500 Subject: [PATCH 2/7] wip --- src/cmd.ts | 8 ++- src/commands/{project => }/cook.ts | 8 +-- src/commands/{project => }/pkg.ts | 8 +-- src/commands/project/build.ts | 58 ----------------- src/commands/project/clean.ts | 42 ------------ src/commands/project/index.ts | 18 ------ src/lib/project.ts | 100 ++++++++++++++++++++++++++--- src/lib/utils.ts | 34 ++++++++++ 8 files changed, 139 insertions(+), 137 deletions(-) rename src/commands/{project => }/cook.ts (88%) rename src/commands/{project => }/pkg.ts (93%) delete mode 100644 src/commands/project/build.ts delete mode 100644 src/commands/project/clean.ts delete mode 100644 src/commands/project/index.ts diff --git a/src/cmd.ts b/src/cmd.ts index 522a28a..172fd60 100644 --- a/src/cmd.ts +++ b/src/cmd.ts @@ -8,9 +8,11 @@ import { buildgraph } from './commands/buildgraph/index.ts' import { run } from './commands/run/index.ts' import { engine } from './commands/engine/index.ts' import { info } from './commands/info/index.ts' -import { project } from './commands/project/index.ts' +import { build } from './commands/build/index.ts' import { sln } from './commands/sln/index.ts' import { init } from './commands/init.ts' +import { cook } from './commands/cook.ts' +import { pkg } from './commands/pkg.ts' import { uat } from './commands/uat.ts' import { ubt } from './commands/ubt.ts' import { workflow } from './commands/workflow/index.ts' @@ -55,7 +57,9 @@ export const cli = cmd .command('buildgraph', buildgraph) .command('run', run) .command('engine', engine) - .command('project', project) + .command('build', build) + .command('cook', cook) + .command('pkg', pkg) .command('sln', sln) .command('uasset', uasset) .command('workflow', workflow) diff --git a/src/commands/project/cook.ts b/src/commands/cook.ts similarity index 88% rename from src/commands/project/cook.ts rename to src/commands/cook.ts index 7c88886..32fe039 100644 --- a/src/commands/project/cook.ts +++ b/src/commands/cook.ts @@ -1,9 +1,9 @@ import { Command, EnumType } from '@cliffy/command' -import { createProject } from '../../lib/project.ts' -import type { GlobalOptions } from '../../lib/types.ts' -import { Config } from '../../lib/config.ts' -import { CookTarget } from '../../lib/engine.ts' +import { createProject } from '../lib/project.ts' +import type { GlobalOptions } from '../lib/types.ts' +import { Config } from '../lib/config.ts' +import { CookTarget } from '../lib/engine.ts' export type CookOptions = typeof cook extends Command ? Options diff --git a/src/commands/project/pkg.ts b/src/commands/pkg.ts similarity index 93% rename from src/commands/project/pkg.ts rename to src/commands/pkg.ts index 782d9ad..2d8597b 100644 --- a/src/commands/project/pkg.ts +++ b/src/commands/pkg.ts @@ -1,7 +1,7 @@ import { Command, EnumType } from '@cliffy/command' -import { Config } from '../../lib/config.ts' -import { createProject } from '../../lib/project.ts' -import type { GlobalOptions } from '../../lib/types.ts' +import { Config } from '../lib/config.ts' +import { createProject } from '../lib/project.ts' +import type { GlobalOptions } from '../lib/types.ts' import { CookStyle, CookTarget, @@ -10,7 +10,7 @@ import { EngineTarget, GameTarget, getPlatformCookTarget, -} from '../../lib/engine.ts' +} from '../lib/engine.ts' export type PkgOptions = typeof pkg extends Command ? Options : never diff --git a/src/commands/project/build.ts b/src/commands/project/build.ts deleted file mode 100644 index dce1d21..0000000 --- a/src/commands/project/build.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Command, EnumType } from '@cliffy/command' - -import { Engine, EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' -import { createProject } from '../../lib/project.ts' -import type { GlobalOptions } from '../../lib/types.ts' -import { Config } from '../../lib/config.ts' - -export type CompileOptions = typeof build extends Command - ? Options - : never - -export const build = new Command() - .description('Builds a target. Can be Editor, Client, Server, or Game') - .type('Target', new EnumType(EngineTarget)) - .type('Configuration', new EnumType(EngineConfiguration)) - .type('Platform', new EnumType(EnginePlatform)) - .arguments(' [ubtArgs...]') - .option('-p, --platform ', 'Platform to build, defaults to host platform', { - default: Engine.getCurrentPlatform(), - }) - .option('-c, --configuration ', 'Configuration to build, defaults to Development', { - default: EngineConfiguration.Development, - }) - .option('--clean', 'Clean the current build first', { default: false }) - .option('--nouht', 'Skips building UnrealHeaderTool', { default: false }) - .option('--noxge', 'Disables Incredibuild', { default: true }) - .option('--dry-run', 'Dry run', { default: false }) - .stopEarly() - .action(async (options, target = EngineTarget.Editor, ...ubtArgs: Array) => { - const { platform, configuration, dryRun, clean, nouht, noxge } = options as CompileOptions - - const config = Config.getInstance() - const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ - cliOptions: options, - }) - const project = await createProject(enginePath, projectPath) - - if (options.clean) { - const result = await project.compile({ - target: target as EngineTarget, - configuration: configuration as EngineConfiguration, - platform: platform as EnginePlatform, - dryRun: dryRun, - clean: true, - }) - } - - await project.compile({ - target: target as EngineTarget, - configuration: configuration as EngineConfiguration, - platform: platform as EnginePlatform, - dryRun: dryRun, - extraArgs: ubtArgs, - clean: false, - nouht: nouht, - noxge: noxge, - }) - }) diff --git a/src/commands/project/clean.ts b/src/commands/project/clean.ts deleted file mode 100644 index 7d14fd9..0000000 --- a/src/commands/project/clean.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Command, EnumType } from '@cliffy/command' - -import { Engine, EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' -import { createProject } from '../../lib/project.ts' -import type { GlobalOptions } from '../../lib/types.ts' -import { Config } from '../../lib/config.ts' - -export type CleanOptions = typeof clean extends Command - ? Options - : never - -export const clean = new Command() - .description('Cleans the output of a target build') - .type('Target', new EnumType(EngineTarget)) - .type('Configuration', new EnumType(EngineConfiguration)) - .type('Platform', new EnumType(EnginePlatform)) - .arguments(' [ubtArgs...]') - .option('-p, --platform ', 'Platform to build, defaults to host platform', { - default: Engine.getCurrentPlatform(), - }) - .option('-c, --configuration ', 'Configuration to build, defaults to Development', { - default: EngineConfiguration.Development, - }) - .option('--dry-run', 'Dry run', { default: false }) - .stopEarly() - .action(async (options, target = EngineTarget.Editor, ...ubtArgs: Array) => { - const { platform, configuration, dryRun } = options as CleanOptions - - const config = Config.getInstance() - const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ - cliOptions: options, - }) - const project = await createProject(enginePath, projectPath) - - await project.compile({ - target: target as EngineTarget, - configuration: configuration as EngineConfiguration, - platform: platform as EnginePlatform, - dryRun: dryRun, - clean: true, - }) - }) diff --git a/src/commands/project/index.ts b/src/commands/project/index.ts deleted file mode 100644 index 3087ada..0000000 --- a/src/commands/project/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Command } from '@cliffy/command' - -import type { GlobalOptions } from '../../lib/types.ts' - -import { build } from './build.ts' -import { clean } from './clean.ts' -import { cook } from './cook.ts' -import { pkg } from './pkg.ts' - -export const project = new Command() - .description('project') - .action(function () { - this.showHelp() - }) - .command('build', build) - .command('clean', clean) - .command('cook', cook) - .command('pkg', pkg) diff --git a/src/lib/project.ts b/src/lib/project.ts index 889c273..b6c56dd 100644 --- a/src/lib/project.ts +++ b/src/lib/project.ts @@ -13,7 +13,7 @@ import { GameTarget, TargetInfo, } from '../lib/engine.ts' -import { copyBuildGraphScripts, exec, findProjectFile } from '../lib/utils.ts' +import { copyBuildGraphScripts, exec, findProjectFile, parseCSForTargetType } from '../lib/utils.ts' const TargetError = (target: string, targets: string[]) => { return new ValidationError(`Invalid Target: ${target} @@ -92,6 +92,7 @@ export class Project { clean = false, nouht = false, noxge = true, + projected = true, }: { target?: EngineTarget | GameTarget configuration?: EngineConfiguration @@ -101,9 +102,45 @@ export class Project { clean?: boolean nouht?: boolean noxge?: boolean + projected?: boolean + }) { + const projectTarget = await this.getProjectTarget(target) + + this.compileTarget({ + target: projectTarget, + configuration: configuration, + platform: platform, + extraArgs: extraArgs, + dryRun: dryRun, + clean: clean, + nouht: nouht, + noxge: noxge, + projected: projected, + }) + } + + async compileTarget({ + target, + configuration = EngineConfiguration.Development, + extraArgs = [], + dryRun = false, + platform = this.engine.getPlatformName(), + clean = false, + nouht = false, + noxge = true, + projected = false, + }: { + target: string + configuration?: EngineConfiguration + platform?: EnginePlatform + extraArgs?: string[] + dryRun?: boolean + clean?: boolean + nouht?: boolean + noxge?: boolean + projected?: boolean }) { const args = [ - this.projectFileVars.projectArgument, '-NoUBTMakefiles', '-NoHotReload', '-NoCodeSign', @@ -113,6 +150,9 @@ export class Project { ...extraArgs, ] + if (projected) { + args.push(this.projectFileVars.projectArgument) + } if (noxge) { args.push('-NoXGE') } @@ -123,10 +163,10 @@ export class Project { args.push('-NoBuildUHT') } - const projectTarget = await this.getProjectTarget(target) + await this.checkTarget(target) await this.engine.runUBT({ - target: projectTarget, + target: target, configuration: configuration, platform: platform, extraArgs: args, @@ -135,12 +175,12 @@ export class Project { } async getProjectTarget(target: EngineTarget | GameTarget): Promise { - let projectTarget = `${this.projectFileVars.projectName}` - if (target != EngineTarget.Game) { - projectTarget = projectTarget + `${target}` + const targetResult = await this.getTargetByType(target) + if (targetResult && targetResult.className) { + return targetResult.className + } else { + return `Unreal${target}` } - await this.checkTarget(projectTarget) - return projectTarget } async package({ @@ -294,6 +334,48 @@ export class Project { } } + async readTargets(targetDir: string): Promise< + Array<{ + className: string | null + targetType: string | null + }> + > { + const targetArray: Array<{ + className: string | null + targetType: string | null + }> = [] + + const files = await Deno.readDir(targetDir) + for await (const file of files) { + if (file.isFile && file.name.endsWith('.cs')) { + const result = await parseCSForTargetType(path.join(targetDir, file.name)) + targetArray.push(result) + } + } + + return targetArray + } + + async getTargetByType(targetType: EngineTarget | GameTarget): Promise< + { + className: string | null + targetType: string | null + } | null + > { + let outTarget = null + const targetDir = path.join(this.projectFileVars.projectDir, 'Source') + + const targets = await this.readTargets(targetDir) + + targets.forEach((target) => { + if (target.targetType == targetType) { + outTarget = target + } + }) + + return outTarget + } + async genProjectFiles(args: string[]) { // Generate project // GenerateProjectFiles.bat -project=E:\Project\TestProject.uproject -game -engine diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 3de61a0..175edd5 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -435,3 +435,37 @@ export async function findFilesByExtension( return files } + +export async function parseCSForTargetType(filePath: string): Promise<{ + className: string | null + targetType: string | null +}> { + // Read the file + const fileContent = await Deno.readTextFile(filePath) + + // Results object + const result = { + className: null as string | null, + targetType: null as string | null, + } + + // Find the class name using regex + const classRegex = /class\s+(\S+)Target[\s:]/g + let classMatch + + while ((classMatch = classRegex.exec(fileContent)) !== null) { + result.className = classMatch[1] + break // Get only the first class name + } + + // Find variables named TargetType + // This pattern looks for field declarations that have 'TargetType' as variable name + const targetTypeRegex = /\s*TargetType\.(.+)\s*;/g + let targetTypeMatch + + while ((targetTypeMatch = targetTypeRegex.exec(fileContent)) !== null) { + result.targetType = targetTypeMatch[1] + } + + return result +} From 95cf343ebbe104c58351c65e0f29e59313975bae Mon Sep 17 00:00:00 2001 From: charlie-runreal Date: Tue, 13 May 2025 20:15:43 -0500 Subject: [PATCH 3/7] test branch update --- .buildkite/pipeline.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 57b0cd3..40dd36c 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -50,6 +50,7 @@ steps: label: ":cityscape: acme build" build: message: ":test_tube: test runreal/cli ${BUILDKITE_BRANCH}-${BUILDKITE_COMMIT}" + branch: cc-refactor env: RUNREAL_FROM_SOURCE: true RUNREAL_FROM_REF: $BUILDKITE_COMMIT From bf3605686f1ed8a746392f5242e05039957f9329 Mon Sep 17 00:00:00 2001 From: charlie-runreal Date: Tue, 13 May 2025 20:20:33 -0500 Subject: [PATCH 4/7] wip --- .gitignore | 1 + src/commands/build/clean.ts | 45 ++++++++++++++++++++++++++ src/commands/build/client.ts | 60 +++++++++++++++++++++++++++++++++++ src/commands/build/editor.ts | 60 +++++++++++++++++++++++++++++++++++ src/commands/build/game.ts | 60 +++++++++++++++++++++++++++++++++++ src/commands/build/index.ts | 22 +++++++++++++ src/commands/build/program.ts | 60 +++++++++++++++++++++++++++++++++++ src/commands/build/server.ts | 60 +++++++++++++++++++++++++++++++++++ 8 files changed, 368 insertions(+) create mode 100644 src/commands/build/clean.ts create mode 100644 src/commands/build/client.ts create mode 100644 src/commands/build/editor.ts create mode 100644 src/commands/build/game.ts create mode 100644 src/commands/build/index.ts create mode 100644 src/commands/build/program.ts create mode 100644 src/commands/build/server.ts diff --git a/.gitignore b/.gitignore index 6e536f2..6493e58 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build +!src/commands/build scratch/ # This file is generated by the runreal CLI during the test .runreal diff --git a/src/commands/build/clean.ts b/src/commands/build/clean.ts new file mode 100644 index 0000000..e9965d3 --- /dev/null +++ b/src/commands/build/clean.ts @@ -0,0 +1,45 @@ +import { Command, EnumType } from '@cliffy/command' + +import { Engine, EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' +import { createProject } from '../../lib/project.ts' +import type { GlobalOptions } from '../../lib/types.ts' +import { Config } from '../../lib/config.ts' + +export type CleanOptions = typeof clean extends Command + ? Options + : never + +export const clean = new Command() + .description('Cleans the output of a target build') + .type('Target', new EnumType(EngineTarget)) + .type('Configuration', new EnumType(EngineConfiguration)) + .type('Platform', new EnumType(EnginePlatform)) + .arguments(' [ubtArgs...]') + .option('--projected', 'Add the -project argument. Defaults to true', { default: true }) + .option('-p, --platform ', 'Platform to build, defaults to host platform', { + default: Engine.getCurrentPlatform(), + }) + .option('-c, --configuration ', 'Configuration to build, defaults to Development', { + default: EngineConfiguration.Development, + }) + .option('--dry-run', 'Dry run', { default: false }) + .stopEarly() + .action(async (options, target = EngineTarget.Editor, ...ubtArgs: Array) => { + const { platform, configuration, dryRun, projected } = options as CleanOptions + + const config = Config.getInstance() + const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ + cliOptions: options, + }) + const project = await createProject(enginePath, projectPath) + + await project.compile({ + target: target as EngineTarget, + configuration: configuration as EngineConfiguration, + platform: platform as EnginePlatform, + dryRun: dryRun, + clean: true, + projected: projected, + extraArgs: ubtArgs, + }) + }) diff --git a/src/commands/build/client.ts b/src/commands/build/client.ts new file mode 100644 index 0000000..42270fc --- /dev/null +++ b/src/commands/build/client.ts @@ -0,0 +1,60 @@ +import { Command, EnumType } from '@cliffy/command' + +import { Engine, EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' +import { createProject } from '../../lib/project.ts' +import type { GlobalOptions } from '../../lib/types.ts' +import { Config } from '../../lib/config.ts' + +export type CompileOptions = typeof client extends Command + ? Options + : never + +export const client = new Command() + .description('Builds the client runtime') + .type('Configuration', new EnumType(EngineConfiguration)) + .type('Platform', new EnumType(EnginePlatform)) + .arguments('[ubtArgs...]') + .option('--projected', 'Add the -project argument. Defaults to true', { default: true }) + .option('-p, --platform ', 'Platform to build, defaults to host platform', { + default: Engine.getCurrentPlatform(), + }) + .option('-c, --configuration ', 'Configuration to build, defaults to Development', { + default: EngineConfiguration.Development, + }) + .option('--clean', 'Clean the current build first', { default: false }) + .option('--nouht', 'Skips building UnrealHeaderTool', { default: false }) + .option('--noxge', 'Disables Incredibuild', { default: true }) + .option('--dry-run', 'Dry run', { default: false }) + .stopEarly() + .action(async (options, ...ubtArgs: Array) => { + const { platform, configuration, dryRun, clean, nouht, noxge, projected } = options as CompileOptions + + const config = Config.getInstance() + const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ + cliOptions: options, + }) + const project = await createProject(enginePath, projectPath) + + if (clean) { + await project.compile({ + target: EngineTarget.Client, + configuration: configuration as EngineConfiguration, + platform: platform as EnginePlatform, + dryRun: dryRun, + clean: true, + projected: projected, + }) + } + + await project.compile({ + target: EngineTarget.Client, + configuration: configuration as EngineConfiguration, + platform: platform as EnginePlatform, + dryRun: dryRun, + extraArgs: ubtArgs, + clean: false, + nouht: nouht, + noxge: noxge, + projected: projected, + }) + }) diff --git a/src/commands/build/editor.ts b/src/commands/build/editor.ts new file mode 100644 index 0000000..28944b5 --- /dev/null +++ b/src/commands/build/editor.ts @@ -0,0 +1,60 @@ +import { Command, EnumType } from '@cliffy/command' + +import { Engine, EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' +import { createProject } from '../../lib/project.ts' +import type { GlobalOptions } from '../../lib/types.ts' +import { Config } from '../../lib/config.ts' + +export type CompileOptions = typeof editor extends Command + ? Options + : never + +export const editor = new Command() + .description('Builds the editor') + .type('Configuration', new EnumType(EngineConfiguration)) + .type('Platform', new EnumType(EnginePlatform)) + .arguments('[ubtArgs...]') + .option('--projected', 'Add the -project argument. Defaults to true', { default: true }) + .option('-p, --platform ', 'Platform to build, defaults to host platform', { + default: Engine.getCurrentPlatform(), + }) + .option('-c, --configuration ', 'Configuration to build, defaults to Development', { + default: EngineConfiguration.Development, + }) + .option('--clean', 'Clean the current build first', { default: false }) + .option('--nouht', 'Skips building UnrealHeaderTool', { default: false }) + .option('--noxge', 'Disables Incredibuild', { default: true }) + .option('--dry-run', 'Dry run', { default: false }) + .stopEarly() + .action(async (options, ...ubtArgs: Array) => { + const { platform, configuration, dryRun, clean, nouht, noxge, projected } = options as CompileOptions + + const config = Config.getInstance() + const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ + cliOptions: options, + }) + const project = await createProject(enginePath, projectPath) + + if (clean) { + await project.compile({ + target: EngineTarget.Editor, + configuration: configuration as EngineConfiguration, + platform: platform as EnginePlatform, + dryRun: dryRun, + clean: true, + projected: projected, + }) + } + + await project.compile({ + target: EngineTarget.Editor, + configuration: configuration as EngineConfiguration, + platform: platform as EnginePlatform, + dryRun: dryRun, + extraArgs: ubtArgs, + clean: false, + nouht: nouht, + noxge: noxge, + projected: projected, + }) + }) diff --git a/src/commands/build/game.ts b/src/commands/build/game.ts new file mode 100644 index 0000000..5e2170e --- /dev/null +++ b/src/commands/build/game.ts @@ -0,0 +1,60 @@ +import { Command, EnumType } from '@cliffy/command' + +import { Engine, EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' +import { createProject } from '../../lib/project.ts' +import type { GlobalOptions } from '../../lib/types.ts' +import { Config } from '../../lib/config.ts' + +export type CompileOptions = typeof game extends Command + ? Options + : never + +export const game = new Command() + .description('Builds the game runtime') + .type('Configuration', new EnumType(EngineConfiguration)) + .type('Platform', new EnumType(EnginePlatform)) + .arguments('[ubtArgs...]') + .option('--projected', 'Add the -project argument. Defaults to true', { default: true }) + .option('-p, --platform ', 'Platform to build, defaults to host platform', { + default: Engine.getCurrentPlatform(), + }) + .option('-c, --configuration ', 'Configuration to build, defaults to Development', { + default: EngineConfiguration.Development, + }) + .option('--clean', 'Clean the current build first', { default: false }) + .option('--nouht', 'Skips building UnrealHeaderTool', { default: false }) + .option('--noxge', 'Disables Incredibuild', { default: true }) + .option('--dry-run', 'Dry run', { default: false }) + .stopEarly() + .action(async (options, ...ubtArgs: Array) => { + const { platform, configuration, dryRun, clean, nouht, noxge, projected } = options as CompileOptions + + const config = Config.getInstance() + const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ + cliOptions: options, + }) + const project = await createProject(enginePath, projectPath) + + if (clean) { + await project.compile({ + target: EngineTarget.Game, + configuration: configuration as EngineConfiguration, + platform: platform as EnginePlatform, + dryRun: dryRun, + clean: true, + projected: projected, + }) + } + + await project.compile({ + target: EngineTarget.Game, + configuration: configuration as EngineConfiguration, + platform: platform as EnginePlatform, + dryRun: dryRun, + extraArgs: ubtArgs, + clean: false, + nouht: nouht, + noxge: noxge, + projected: projected, + }) + }) diff --git a/src/commands/build/index.ts b/src/commands/build/index.ts new file mode 100644 index 0000000..5a9733e --- /dev/null +++ b/src/commands/build/index.ts @@ -0,0 +1,22 @@ +import { Command } from '@cliffy/command' + +import type { GlobalOptions } from '../../lib/types.ts' + +import { client } from './client.ts' +import { clean } from './clean.ts' +import { editor } from './editor.ts' +import { game } from './game.ts' +import { program } from './program.ts' +import { server } from './server.ts' + +export const build = new Command() + .description('build') + .action(function () { + this.showHelp() + }) + .command('client', client) + .command('clean', clean) + .command('editor', editor) + .command('game', game) + .command('program', program) + .command('server', server) diff --git a/src/commands/build/program.ts b/src/commands/build/program.ts new file mode 100644 index 0000000..917457f --- /dev/null +++ b/src/commands/build/program.ts @@ -0,0 +1,60 @@ +import { Command, EnumType } from '@cliffy/command' + +import { Engine, EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' +import { createProject } from '../../lib/project.ts' +import type { GlobalOptions } from '../../lib/types.ts' +import { Config } from '../../lib/config.ts' + +export type CompileOptions = typeof program extends Command + ? Options + : never + +export const program = new Command() + .description('Builds a program') + .type('Configuration', new EnumType(EngineConfiguration)) + .type('Platform', new EnumType(EnginePlatform)) + .arguments(' [ubtArgs...]') + .option('--projected', 'Add the -project argument. Defaults to false', { default: false }) + .option('-p, --platform ', 'Platform to build, defaults to host platform', { + default: Engine.getCurrentPlatform(), + }) + .option('-c, --configuration ', 'Configuration to build, defaults to Development', { + default: EngineConfiguration.Development, + }) + .option('--clean', 'Clean the current build first', { default: false }) + .option('--nouht', 'Skips building UnrealHeaderTool', { default: false }) + .option('--noxge', 'Disables Incredibuild', { default: true }) + .option('--dry-run', 'Dry run', { default: false }) + .stopEarly() + .action(async (options, program: string, ...ubtArgs: Array) => { + const { platform, configuration, dryRun, clean, nouht, noxge, projected } = options as CompileOptions + + const config = Config.getInstance() + const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ + cliOptions: options, + }) + const project = await createProject(enginePath, projectPath) + + if (clean) { + await project.compileTarget({ + target: program, + configuration: configuration as EngineConfiguration, + platform: platform as EnginePlatform, + dryRun: dryRun, + clean: true, + projected: projected, + }) + } + + await project.compileTarget({ + target: program, + configuration: configuration as EngineConfiguration, + platform: platform as EnginePlatform, + dryRun: dryRun, + extraArgs: ubtArgs, + clean: false, + nouht: nouht, + noxge: noxge, + projected: projected, + }) + }) diff --git a/src/commands/build/server.ts b/src/commands/build/server.ts new file mode 100644 index 0000000..f4c023c --- /dev/null +++ b/src/commands/build/server.ts @@ -0,0 +1,60 @@ +import { Command, EnumType } from '@cliffy/command' + +import { Engine, EngineConfiguration, EnginePlatform, EngineTarget } from '../../lib/engine.ts' +import { createProject } from '../../lib/project.ts' +import type { GlobalOptions } from '../../lib/types.ts' +import { Config } from '../../lib/config.ts' + +export type CompileOptions = typeof server extends Command + ? Options + : never + +export const server = new Command() + .description('Builds the server runtime') + .type('Configuration', new EnumType(EngineConfiguration)) + .type('Platform', new EnumType(EnginePlatform)) + .arguments('[ubtArgs...]') + .option('--projected', 'Add the -project argument. Defaults to true', { default: true }) + .option('-p, --platform ', 'Platform to build, defaults to host platform', { + default: Engine.getCurrentPlatform(), + }) + .option('-c, --configuration ', 'Configuration to build, defaults to Development', { + default: EngineConfiguration.Development, + }) + .option('--clean', 'Clean the current build first', { default: false }) + .option('--nouht', 'Skips building UnrealHeaderTool', { default: false }) + .option('--noxge', 'Disables Incredibuild', { default: true }) + .option('--dry-run', 'Dry run', { default: false }) + .stopEarly() + .action(async (options, ...ubtArgs: Array) => { + const { platform, configuration, dryRun, clean, nouht, noxge, projected } = options as CompileOptions + + const config = Config.getInstance() + const { engine: { path: enginePath }, project: { path: projectPath } } = config.mergeConfigCLIConfig({ + cliOptions: options, + }) + const project = await createProject(enginePath, projectPath) + + if (clean) { + await project.compile({ + target: EngineTarget.Server, + configuration: configuration as EngineConfiguration, + platform: platform as EnginePlatform, + dryRun: dryRun, + clean: true, + projected: projected, + }) + } + + await project.compile({ + target: EngineTarget.Server, + configuration: configuration as EngineConfiguration, + platform: platform as EnginePlatform, + dryRun: dryRun, + extraArgs: ubtArgs, + clean: false, + nouht: nouht, + noxge: noxge, + projected: projected, + }) + }) From 4efe6764e140f491961f520b709ae172c627aaea Mon Sep 17 00:00:00 2001 From: charlie-runreal Date: Wed, 14 May 2025 09:55:51 -0500 Subject: [PATCH 5/7] wip --- src/lib/project.ts | 10 +++++----- src/lib/utils.ts | 7 ++++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/lib/project.ts b/src/lib/project.ts index b6c56dd..5647d5d 100644 --- a/src/lib/project.ts +++ b/src/lib/project.ts @@ -176,8 +176,8 @@ export class Project { async getProjectTarget(target: EngineTarget | GameTarget): Promise { const targetResult = await this.getTargetByType(target) - if (targetResult && targetResult.className) { - return targetResult.className + if (targetResult && targetResult.targetName) { + return targetResult.targetName } else { return `Unreal${target}` } @@ -336,12 +336,12 @@ export class Project { async readTargets(targetDir: string): Promise< Array<{ - className: string | null + targetName: string | null targetType: string | null }> > { const targetArray: Array<{ - className: string | null + targetName: string | null targetType: string | null }> = [] @@ -358,7 +358,7 @@ export class Project { async getTargetByType(targetType: EngineTarget | GameTarget): Promise< { - className: string | null + targetName: string | null targetType: string | null } | null > { diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 175edd5..cd54616 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -437,7 +437,7 @@ export async function findFilesByExtension( } export async function parseCSForTargetType(filePath: string): Promise<{ - className: string | null + targetName: string | null targetType: string | null }> { // Read the file @@ -445,7 +445,7 @@ export async function parseCSForTargetType(filePath: string): Promise<{ // Results object const result = { - className: null as string | null, + targetName: null as string | null, targetType: null as string | null, } @@ -454,7 +454,7 @@ export async function parseCSForTargetType(filePath: string): Promise<{ let classMatch while ((classMatch = classRegex.exec(fileContent)) !== null) { - result.className = classMatch[1] + result.targetName = classMatch[1] break // Get only the first class name } @@ -465,6 +465,7 @@ export async function parseCSForTargetType(filePath: string): Promise<{ while ((targetTypeMatch = targetTypeRegex.exec(fileContent)) !== null) { result.targetType = targetTypeMatch[1] + break } return result From 650a435f1280398a60f118dabaadb7ea678fcacf Mon Sep 17 00:00:00 2001 From: warman Date: Sat, 17 May 2025 14:13:58 -0400 Subject: [PATCH 6/7] chore: clean up extra console.log --- src/commands/pkg.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/commands/pkg.ts b/src/commands/pkg.ts index 2d8597b..bee67cc 100644 --- a/src/commands/pkg.ts +++ b/src/commands/pkg.ts @@ -57,9 +57,7 @@ export const pkg = new Command() break } - console.log(`${buildargs}`) if (buildargs) { - console.log(`Recieved build arguments - ${buildargs}`) project.compile({ target: target as GameTarget, configuration: configuration as EngineConfiguration, @@ -72,7 +70,6 @@ export const pkg = new Command() args.push('-build') } if (cookargs) { - console.log(`Recieved cook arguments - ${cookargs}`) const cookTarget = getPlatformCookTarget(platform, target) project.cookContent({ target: cookTarget as CookTarget, From c1ba1bf92b1de9dd3cea521b9c0e861ad7786c13 Mon Sep 17 00:00:00 2001 From: warman Date: Sat, 17 May 2025 14:17:33 -0400 Subject: [PATCH 7/7] ci: allow configurable runreal-acme branch --- .buildkite/pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 40dd36c..7efed85 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -50,7 +50,7 @@ steps: label: ":cityscape: acme build" build: message: ":test_tube: test runreal/cli ${BUILDKITE_BRANCH}-${BUILDKITE_COMMIT}" - branch: cc-refactor + branch: ${RUNREAL_ACME_BRANCH:-main} env: RUNREAL_FROM_SOURCE: true RUNREAL_FROM_REF: $BUILDKITE_COMMIT