omegga 1.10.1 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## Latest
4
4
 
5
+ ## 1.11.0 - 2026-07-19
6
+
7
+ - Add `/version` terminal command, warning when the binary on disk differs from the running build
8
+ - Show the game version in the `Launching Brickadia Server` log
9
+ - Fix the game version not being re-detected after a Steam update, and re-emit `version` on restart
10
+
5
11
  ## 1.10.1 - 2026-07-18
6
12
 
7
13
  - Plugins: Fix `getSavePath`/`getPrefabPath`/`getWorldPath` mangling absolute paths
@@ -2,6 +2,7 @@
2
2
  Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
3
  const logger = require("../logger.js");
4
4
  const steam = require("../updater/steam.js");
5
+ const version = require("../omegga/matchers/version.js");
5
6
  const chat = require("../util/chat.js");
6
7
  const wsl = require("../util/wsl.js");
7
8
  const events = require("../webserver/backend/events.js");
@@ -120,6 +121,26 @@ const COMMANDS = [
120
121
  await this.omegga.restartServer();
121
122
  }
122
123
  },
124
+ {
125
+ aliases: ["version", "ver"],
126
+ desc: "print the game version",
127
+ fn() {
128
+ const running = this.omegga.version;
129
+ const binary = version.readBinaryVersion(this.omegga.getGameBinaryPath());
130
+ if (running > 0) log("Brickadia Server", ("CL" + running).green);
131
+ else warn("Game version is not known yet.");
132
+ if (binary == null) return;
133
+ if (running > 0 && binary !== running) {
134
+ warn(
135
+ "Server binary on disk is",
136
+ ("CL" + binary).yellow + ".",
137
+ "Restart to run the updated build."
138
+ );
139
+ } else if (!(running > 0)) {
140
+ log("Server binary on disk is", ("CL" + binary).green);
141
+ }
142
+ }
143
+ },
123
144
  {
124
145
  aliases: ["update"],
125
146
  desc: "try to update the server and restart if started (without announcement or saving",
@@ -1 +1 @@
1
- {"version":3,"file":"terminal.js","sources":["../../src/cli/terminal.ts"],"sourcesContent":["import Logger from '@/logger';\nimport { OmeggaPlayer } from '@/plugin';\nimport { steamcmdCheckUpdate, steamcmdDownloadGame } from '@/updater';\nimport Omegga from '@omegga/server';\nimport { IOmeggaOptions } from '@omegga/types';\nimport { sanitize } from '@util/chat';\nimport { checkWsl } from '@util/wsl';\nimport { serverEvents } from '@webserver/backend/events';\nimport readline from 'readline';\nimport { install } from './plugin';\n\ndeclare global {\n interface String {\n brightRed: string;\n brightGreen: string;\n brightYellow: string;\n brightBlue: string;\n brightMagenta: string;\n brightCyan: string;\n brightWhite: string;\n }\n}\n\nlet log: (...args: any[]) => void,\n err: (...args: any[]) => void,\n warn: (...args: any[]) => void,\n info: (...args: any[]) => void;\n\ntype TerminalCommand = {\n aliases: string[];\n desc: string;\n descLines?: () => string[];\n fn(this: Terminal, ...args: string[]): void | Promise<void>;\n};\n\nfunction gameCommand(\n aliases: string[],\n desc: string,\n usage: string,\n command: string,\n quoteArgs?: boolean,\n): TerminalCommand {\n return {\n aliases,\n desc,\n fn(...args) {\n if (!this.omegga.started) {\n err('The server is not running');\n return;\n }\n if (!args.length) {\n err('usage:', ('/' + aliases[0] + ' ' + usage).yellow);\n return;\n }\n this.omegga.writeln(\n `${command} ${quoteArgs ? '\"' : ''}${args.join(' ')}${\n quoteArgs ? '\"' : ''\n }`,\n );\n this.rl.prompt(true);\n },\n };\n}\n\nconst COMMANDS: TerminalCommand[] = [\n // Brickadia commands\n gameCommand(\n ['kick'],\n 'kick a player',\n '<name|id> [reason]',\n 'Chat.Command /Kick',\n ),\n gameCommand(\n ['ban', 'banish'],\n 'ban a player',\n '<name|id> [time] [reason]',\n 'Ban',\n ),\n gameCommand(\n ['unban', 'pardon'],\n 'unban a player',\n '<name|id>',\n 'Chat.Command /Unban',\n ),\n gameCommand(\n ['grantrole', 'giverole'],\n 'grant a role to a player',\n '<role> <name|id>',\n 'Chat.Command /GrantRole',\n ),\n gameCommand(\n ['revokerole', 'takerole'],\n 'revoke a role from a player',\n '<role> <name|id>',\n 'Chat.Command /RevokeRole',\n ),\n gameCommand(\n ['clearbricks'],\n \"clear a player's bricks\",\n '<name|id>',\n 'Bricks.Clear',\n true,\n ),\n gameCommand(['clearallbricks'], 'clear all bricks', '', 'Bricks.ClearAll'),\n\n // Help command\n {\n aliases: ['help', 'cmds', 'commands'],\n desc: 'list supported commands and their descriptions',\n fn() {\n const maxLen = Math.max(...COMMANDS.map(c => c.aliases[0].length));\n log('Omegga Help Text:\\n');\n log(\n ' Console input not starting with / will be sent in chat from a \"SERVER\" user',\n );\n log(\n ' Console input starting with / will be treated as one of the following commands\\n',\n );\n log(\n '-- Available Omegga commands (type',\n '/command'.yellow.underline,\n 'to run)',\n );\n\n for (const command of COMMANDS.sort((a, b) =>\n a.aliases[0].localeCompare(b.aliases[0]),\n )) {\n const name = command.aliases[0];\n this.log(\n ' ',\n ('/' + name).yellow.underline,\n '-'.padStart(maxLen - name.length + 1),\n command.desc,\n );\n if (command.descLines)\n for (const descLine of command.descLines())\n this.log(' ', ' '.repeat(maxLen + 1), descLine);\n }\n },\n },\n\n // Server controls\n {\n aliases: ['stop', 'exit', 'quit', 'close'],\n desc: 'stop the server and close Omegga',\n async fn() {\n log('Stopping server...');\n await this.omegga.stop();\n process.exit();\n },\n },\n {\n aliases: ['restart'],\n desc: 'trigger a server restart (without announcement or saving)',\n async fn() {\n log('Restarting server...');\n await this.omegga.restartServer();\n },\n },\n {\n aliases: ['update'],\n desc: 'try to update the server and restart if started (without announcement or saving',\n async fn() {\n if (!this.omegga.config.__STEAM) {\n err(\n 'This command is only available when the server is installed via SteamCMD',\n );\n return;\n }\n if (this.omegga.stopping || this.omegga.starting) {\n err(\n 'The server is currently starting or stopping. Please wait a moment',\n );\n return;\n }\n const wasStarted = this.omegga.started;\n if (wasStarted) {\n log('Stopping server to update...');\n await this.omegga.stop();\n }\n log('Updating server...');\n try {\n await steamcmdDownloadGame({\n steambeta: this.omegga.config.server?.steambeta,\n steambetaPassword: this.omegga.config.server?.steambetaPassword,\n });\n log('Server updated successfully.');\n } catch (e) {\n err('Error updating server:', e);\n }\n if (wasStarted) {\n log('Starting server...');\n await this.omegga.start();\n }\n },\n },\n {\n aliases: ['updatecheck', 'uc', 'check'],\n desc: 'check for updates. /uc show for details, /uc on|off to toggle auto-update',\n async fn(subcommand?: string) {\n if (!this.omegga.config.__STEAM) {\n err(\n 'This command is only available when the server is installed via SteamCMD',\n );\n return;\n }\n\n const db = this.omegga.webserver?.database;\n\n if (subcommand === 'on' || subcommand === 'off') {\n if (!db) {\n err('Database not available.');\n return;\n }\n const config = await db.getAutoRestartConfig();\n config.autoUpdateEnabled = subcommand === 'on';\n await db.setAutoRestartConfig(config);\n log(\n subcommand === 'on'\n ? 'Auto-update enabled.'.green\n : 'Auto-update disabled.'.yellow,\n );\n return;\n }\n\n log('Checking for updates...');\n const result = steamcmdCheckUpdate(this.omegga.config.server?.steambeta);\n if (!result) {\n err('Failed to check for updates.');\n return;\n }\n const { local, remote, hasUpdate } = result;\n\n if (hasUpdate === true) log('Update available!'.green);\n else if (hasUpdate === false) log('Up to date.'.green);\n else log('Could not determine update status.'.yellow);\n\n if (subcommand === 'show') {\n const branch =\n local.betaKey && local.betaKey !== 'main' ? local.betaKey : 'public';\n const remoteBuild = remote?.branches?.[branch];\n const remotePart = remoteBuild\n ? `BuildID ${remoteBuild.buildid}` +\n (remoteBuild.timeupdated\n ? ` (${new Date(Number(remoteBuild.timeupdated) * 1000).toLocaleString()})`\n : '')\n : 'unknown (private branch?)';\n log(\n [\n ` Local: BuildID ${local.buildId} (${local.installState})`,\n ` Remote: ${remotePart}`,\n ` Branch: ${local.betaKey ?? 'public'}`,\n ].join('\\n'),\n );\n }\n\n if (db) {\n const config = await db.getAutoRestartConfig();\n log(\n config.autoUpdateEnabled\n ? `Auto-update: enabled (every ${config.autoUpdateIntervalMins}m)`\n : 'Auto-update: disabled',\n );\n }\n },\n },\n {\n aliases: ['kill'],\n desc: 'forcefully kill brickadia server process without closing omegga',\n async fn() {\n log('Stopping server...');\n await this.omegga.stop();\n },\n },\n {\n aliases: ['start'],\n desc: 'start the server if it is stopped',\n fn() {\n if (\n !this.omegga ||\n (this.omegga && (this.omegga.starting || this.omegga.started))\n ) {\n err('The server is already running');\n return;\n }\n\n log('Starting server...');\n this.omegga.start();\n },\n },\n {\n aliases: ['cmd'],\n desc: 'run a console command on the Brickadia server. requires /debug for log to show',\n fn(...args) {\n if (!this.omegga.started) {\n err('The server is not running');\n return;\n }\n this.omegga.writeln(args.join(' '));\n },\n },\n {\n aliases: ['debug'],\n desc: 'toggle visibility of brickadia console logs',\n fn() {\n this.options.debug = !this.options.debug;\n log(\n 'Brickadia logs now',\n this.options.debug ? 'visible'.green : 'hidden'.red,\n );\n },\n },\n {\n aliases: ['status'],\n desc: 'display server status information. brick count, online players, etc',\n async fn() {\n if (!this.omegga.started) {\n err('Omegga is not running');\n return;\n }\n const msToTime = (ms: number) => new Date(ms).toISOString().slice(11, 19);\n try {\n const status = await this.omegga.getServerStatus();\n\n log('Server Status');\n this.log(`\n${status.serverName.yellow}\nBricks: ${(status.bricks + '').yellow}\nComponents: ${(status.components + '').yellow}\nUptime: ${msToTime(status.time).yellow}\nPlayers: ${status.players.length === 0 ? 'none'.grey : ''}\n ${status.players\n .map(p => `[${msToTime(p.time).grey}] ${p.name.brightYellow}`)\n .join('\\n ')}\n`);\n } catch (e) {\n err('An error occurred while getting server status');\n }\n },\n },\n\n // plugin stuff\n {\n aliases: ['reload'],\n desc: 'shorthand for /plugins reload',\n async fn() {\n await COMMANDS.find(c => c.aliases.includes('plugins')).fn.bind(this)(\n 'reload',\n );\n },\n },\n {\n aliases: ['plugins', 'plugin', 'p'],\n desc: 'manage Omegga plugins',\n descLines: () => [\n '/plugins install <...plugin names>'.yellow + ' installs plugins',\n '/plugins load <...plugin names>'.yellow +\n ' loads plugins, and enables if they were disabled',\n '/plugins unload <...plugin names>'.yellow + ' unloads plugins',\n '/plugins reload [...plugin names]'.yellow +\n ' reloads all plugins, or those specified',\n '/plugins enable <...plugin names>'.yellow + ' enables plugins',\n '/plugins disable <...plugin names>'.yellow +\n ' disables plugins, and unloads if they were loaded',\n ],\n async fn(subcommand: string, ...args: string[]) {\n if (!this.omegga.pluginLoader) {\n err('Omegga is not using plugins');\n return;\n }\n\n if (!subcommand) {\n const plugins = this.omegga.pluginLoader.plugins;\n if (plugins.length === 0) {\n log('No plugins are installed');\n log(' Install some with', '/plugins install'.yellow.underline);\n } else {\n log('Installed plugins'.yellow.underline);\n for (const plugin of plugins) {\n const name = plugin.getName();\n const docs = plugin.getDocumentation();\n if (plugin.isLoaded()) log(name.cyan.underline + ' (loaded)');\n else if (plugin.isEnabled())\n log(name.green.underline + ' (enabled, not loaded)');\n else log(name.red.underline + ' (disabled)');\n\n log(' ' + docs.description);\n log((' Author: ' + docs.author).gray);\n }\n }\n } else if (subcommand === 'install') {\n // install plugins\n await install(args, { verbose: true });\n log();\n log(\n 'Use',\n '/plugins reload'.yellow,\n 'to reload all plugins and use the installed ones',\n );\n } else if (subcommand === 'load') {\n if (args.length === 0) {\n log('Please specify at least one plugin to load');\n return;\n }\n\n for (const pluginName of args) {\n const plugin = this.omegga.pluginLoader.plugins.find(\n p => p.getName().toLowerCase() === pluginName.toLowerCase(),\n );\n\n if (!plugin) {\n warn('No plugin by the name', pluginName.cyan);\n continue;\n }\n\n const name = plugin.getName();\n if (plugin.isLoaded()) {\n warn(\n name.cyan,\n 'is already loaded, reload with',\n ('/plugins reload ' + name).yellow,\n );\n return;\n }\n\n if (!plugin.isEnabled()) {\n log('Enabling and loading', name.cyan.underline);\n plugin.setEnabled(true);\n await plugin.load();\n } else {\n log('Loading', name.cyan.underline);\n await plugin.load();\n }\n }\n } else if (subcommand === 'unload') {\n if (args.length === 0) {\n log('Please specify at least one plugin to unload');\n return;\n }\n\n for (const pluginName of args) {\n const plugin = this.omegga.pluginLoader.plugins.find(\n p => p.getName().toLowerCase() === pluginName.toLowerCase(),\n );\n\n if (!plugin) {\n warn('No plugin by the name', pluginName.cyan);\n continue;\n }\n\n const name = plugin.getName();\n if (!plugin.isLoaded()) {\n warn(\n name.cyan,\n 'is already unloaded, load with',\n ('/plugins load ' + name).yellow,\n );\n return;\n }\n\n log('Unloading', name.cyan.underline);\n await plugin.unload();\n }\n } else if (subcommand === 'reload') {\n let plugins = (\n args.length === 0\n ? this.omegga.pluginLoader.plugins\n : this.omegga.pluginLoader.plugins.filter(p =>\n args\n .map(a => a.toLowerCase())\n .includes(p.getName().toLowerCase()),\n )\n ).filter(p => p.isEnabled());\n\n const loaded = plugins.filter(p => p.isLoaded());\n log('Unloading', loaded.length, 'plugins');\n for (const plugin of loaded) await plugin.unload();\n\n if (args.length === 0) {\n log('Scanning for new plugins');\n if (!(await this.omegga.pluginLoader.scan())) {\n err('Could not scan for plugins. All plugins are unloaded');\n return;\n }\n }\n\n plugins = (\n args.length === 0\n ? this.omegga.pluginLoader.plugins\n : this.omegga.pluginLoader.plugins.filter(p =>\n args\n .map(a => a.toLowerCase())\n .includes(p.getName().toLowerCase()),\n )\n ).filter(p => p.isEnabled());\n log('Loading', plugins.length, 'plugins');\n for (const plugin of plugins) await plugin.load();\n\n log('Reloaded', plugins.length, 'plugins');\n } else if (subcommand === 'enable') {\n if (args.length === 0) {\n log('Please specify at least one plugin to enable');\n return;\n }\n\n for (const pluginName of args) {\n const plugin = this.omegga.pluginLoader.plugins.find(\n p => p.getName().toLowerCase() === pluginName.toLowerCase(),\n );\n\n if (!plugin) {\n warn('No plugin by the name', pluginName.cyan);\n continue;\n }\n\n const name = plugin.getName();\n if (plugin.isEnabled()) {\n warn(\n name.cyan,\n 'is already enabled, disable with',\n ('/plugins disable ' + name).yellow,\n );\n return;\n }\n\n log(\n 'Enabling',\n name.cyan.underline,\n '(load with',\n ('/plugins load ' + name).yellow + ')',\n );\n plugin.setEnabled(true);\n }\n } else if (subcommand === 'disable') {\n if (args.length === 0) {\n log('Please specify at least one plugin to disable');\n return;\n }\n\n for (const pluginName of args) {\n const plugin = this.omegga.pluginLoader.plugins.find(\n p => p.getName().toLowerCase() === pluginName.toLowerCase(),\n );\n\n if (!plugin) {\n warn('No plugin by the name', pluginName.cyan);\n continue;\n }\n\n const name = plugin.getName();\n if (!plugin.isEnabled()) {\n warn(\n name.cyan,\n 'is already disabled, enable with',\n ('/plugins enable ' + name).yellow,\n );\n return;\n }\n\n if (plugin.isLoaded()) {\n log('Unloading and disabling', name.cyan.underline);\n await plugin.unload();\n plugin.setEnabled(false);\n } else {\n log('Disabling', name.cyan.underline);\n plugin.setEnabled(false);\n }\n }\n }\n },\n },\n {\n aliases: ['world', 'worlds', 'w'],\n desc: 'Manage worlds on the server',\n descLines: () => ['Type /worlds load a world'],\n async fn(subcommand: string, ...args: string[]) {\n switch (subcommand) {\n default:\n const commands = [\n {\n command: '/worlds use [world]',\n desc: 'set or remove a world as the default world for startup',\n short: '/w u [world]',\n },\n {\n command: '/worlds load <world> [rev]',\n desc: 'load a world',\n short: '/w load <world> [rev]',\n },\n {\n command: '/worlds saveas <world>',\n desc: 'save the current world as a new world',\n short: '/w sa <world>',\n },\n {\n command: '/worlds save',\n desc: 'save the current world',\n short: '/w s',\n },\n {\n command: '/worlds revisions <world>',\n desc: 'list revisions of a world',\n short: '/w r <world>',\n },\n {\n command: '/worlds new',\n desc: 'create a new world',\n short: '/w new <name> [Plate|Space|Studio|Peaks]',\n },\n ];\n log(\n 'Default world is',\n this.omegga.getNextWorld()?.file?.yellow || 'none'.grey,\n );\n log('Available world commands:');\n for (const { command, desc, short } of commands) {\n this.log(' ', command.yellow, '-', desc, `(${short.yellow})`);\n }\n return;\n\n case 'use':\n case 'u':\n const world = args[0]?.replace(/\\.brdb$/, '');\n if (world && !this.omegga.worldExists(world)) {\n err(`World \"${world}\" does not exist`);\n return;\n }\n if (this.omegga.setActiveWorld(world || null)) {\n if (world) {\n log(\n `Default world set to ${world.yellow}. It will be loaded next startup.`,\n );\n } else {\n log(\n 'Default world cleared. No world will be loaded on next startup.',\n );\n }\n } else {\n err(`Failed to set default world to ${world.yellow}.`);\n }\n return;\n\n case 'list':\n case 'ls':\n // list worlds\n const worlds = this.omegga.getWorlds();\n if (worlds.length === 0) {\n log(\n 'No worlds found. Create one with',\n '/worlds saveas <world>'.yellow,\n );\n } else {\n log('Available worlds:');\n const prefix = this.omegga.worldPath + '/';\n for (const world of worlds) {\n this.log(\n ' ',\n world.replace(prefix, '').replace(/\\.brdb$/, '').yellow,\n );\n }\n }\n return;\n case 'load':\n case 'l':\n if (!this.omegga.started) {\n err('The server is not running');\n return;\n }\n\n // load a world\n if (args.length === 0) {\n err('Please specify a world to load');\n return;\n }\n const worldName = args[0].replace(/\\.brdb$/, '');\n if (!this.omegga.getWorldPath(worldName)) {\n err(`World \"${worldName}\" does not exist`);\n return;\n }\n let revision: number | undefined;\n if (args.length > 1) {\n revision = parseInt(args[1], 10);\n if (isNaN(revision) || revision < 1) {\n err(`Invalid revision number: ${args[1]}`);\n return;\n }\n }\n let loadRes: boolean = false;\n if (revision) {\n log(`Loading world ${worldName.yellow} at revision ${revision}...`);\n loadRes = await this.omegga.loadWorldRevision(worldName, revision);\n } else {\n log(`Loading world ${worldName.yellow}...`);\n loadRes = await this.omegga.loadWorld(worldName);\n }\n if (loadRes) {\n log(`World ${worldName.yellow} loaded successfully.`);\n } else {\n err(`Failed to load world ${worldName.yellow}`);\n }\n\n return;\n case 'saveas':\n case 'sa':\n if (!this.omegga.started) {\n err('The server is not running');\n return;\n }\n\n // save the current world as a new world\n if (args.length === 0) {\n err('Please specify a world to save as');\n return;\n }\n const saveWorldName = args[0].replace(/\\.brdb$/, '');\n if (this.omegga.getWorldPath(saveWorldName)) {\n err(`World \"${saveWorldName}\" already exists`);\n return;\n }\n log(`Saving current world as ${saveWorldName.yellow}...`);\n const saveAsRes = await this.omegga.saveWorldAs(saveWorldName);\n if (saveAsRes) {\n log(`Current world saved as ${saveWorldName.yellow} successfully.`);\n } else {\n err(`Failed to save current world as ${saveWorldName.yellow}`);\n }\n return;\n\n case 'save':\n case 's':\n if (!this.omegga.started) {\n err('The server is not running');\n return;\n }\n\n // save the current world\n log('Saving current world...');\n const res = await this.omegga.saveWorld();\n if (res) {\n log('Current world saved successfully.');\n } else {\n err('Failed to save the current world');\n }\n return;\n\n case 'revisions':\n case 'r':\n if (!this.omegga.started) {\n err('The server is not running');\n return;\n }\n\n // list revisions of a world\n if (args.length === 0) {\n err('Please specify a world to list revisions for');\n return;\n }\n const revisionsWorldName = args[0].replace(/\\.brdb$/, '');\n if (!this.omegga.getWorldPath(revisionsWorldName)) {\n err(`World \"${revisionsWorldName}\" does not exist`);\n return;\n }\n log(`Listing revisions for world ${revisionsWorldName.yellow}...`);\n try {\n const revisions =\n await this.omegga.getWorldRevisions(revisionsWorldName);\n if (revisions.length === 0) {\n log('No revisions found for world', revisionsWorldName.yellow);\n } else {\n log('Revisions for world', revisionsWorldName.yellow + ':');\n for (const rev of revisions) {\n this.log(\n ' ',\n `Revision ${rev.index.toString().yellow} - ${\n rev.date\n .toISOString()\n .replace('T', ' ')\n .replace('.000Z', '').blue\n }`,\n `(${rev.note})`.grey,\n );\n }\n }\n } catch (e) {\n err(\n 'An error occurred while getting world revisions:',\n e.toString(),\n );\n }\n return;\n\n case 'new':\n case 'n':\n if (!this.omegga.started) {\n err('The server is not running');\n return;\n }\n\n // create a new world\n if (args.length === 0) {\n err('Please specify a name for the new world');\n return;\n }\n const newWorldName = args[0].replace(/\\.brdb$/, '');\n if (this.omegga.getWorldPath(newWorldName)) {\n err(`World \"${newWorldName}\" already exists`);\n return;\n }\n const map = (args[1] ? args[1] : 'Plate') as\n | 'Plate'\n | 'Space'\n | 'Studio'\n | 'Peaks';\n if (!['Plate', 'Space', 'Studio', 'Peaks'].includes(map)) {\n err(`Invalid preset \"${map}\". Valid map are: Plate, Space, Studio`);\n return;\n }\n log(`Creating new world ${newWorldName.yellow}...`);\n this.omegga.createEmptyWorld(newWorldName, map);\n }\n },\n },\n {\n aliases: ['user'],\n desc: 'manage web UI users',\n descLines: () => [\n \"/user passwd <username> - Reset a user's password\",\n '/user resetmfa <username> - Clear TOTP and passkeys',\n ],\n async fn(subcommand?: string, username?: string) {\n const db = this.omegga.webserver?.database;\n if (!db) {\n err('Database not available.');\n return;\n }\n if (!subcommand || !username) {\n err('Usage: /user <passwd|resetmfa> <username>');\n return;\n }\n if (!(await db.userExists(username))) {\n err(`User \"${username}\" does not exist.`);\n return;\n }\n switch (subcommand) {\n case 'passwd': {\n const password = await new Promise<string>(resolve =>\n this.rl.question('New password: ', resolve),\n );\n if (!password) {\n err('Password cannot be empty.');\n return;\n }\n await db.userPasswd(username, password);\n log(`Password updated for \"${username.yellow}\".`);\n break;\n }\n case 'resetmfa': {\n await db.resetUserMfa(username);\n log(\n `MFA cleared for \"${username.yellow}\" (TOTP, passkeys, recovery codes).`,\n );\n break;\n }\n default:\n err(`Unknown subcommand \"${subcommand}\". Use passwd or resetmfa.`);\n }\n },\n },\n];\n\n// the terminal wraps omegga and displays console output and handles console input\nexport default class Terminal {\n options: IOmeggaOptions;\n omegga: Omegga;\n rl: readline.Interface;\n constructor(omegga: Omegga, options: IOmeggaOptions = {}) {\n this.options = options;\n this.omegga = omegga;\n\n // terminal interface\n this.rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n terminal: true,\n });\n this.rl.setPrompt('> '.brightGreen);\n\n // shortand fns\n log = (...args) => this.log('>>'.green, ...args);\n err = (...args) => this.error('!>'.red, ...args);\n info = (...args) => this.log('?>'.blue, ...args);\n warn = (...args) => this.warn('W>'.yellow, ...args);\n\n // print log line if debug is enabled\n let launcherDone = false;\n let lastDoneMessage = '';\n omegga.on('line', l => {\n // Redact the hosting token only in what we print to the debug log.\n // Brickadia echoes its full command line (including -Token=\"...\") via a\n // LogInit line on stdout; restrict the redaction to engine log lines\n // (LogInit/etc.) so we don't mangle other output (e.g. chat) that might\n // legitimately contain a -Token= string. The raw `l` is still delivered\n // to matchers/plugins elsewhere, so this must not mutate that value.\n if (options.debug)\n this.log(\n '::'.blue,\n /^Log\\w+:/.test(l)\n ? l.replace(/-Token=\"[^\"]*\"/, '-Token=\"REDACTED\"')\n : l,\n );\n else if (!launcherDone) {\n if (l.match(/Update Failed/)) {\n err(l);\n info(\n 'This might be resolved by deleting brickadia and reinstalling:',\n );\n info(' rm -rf ~/.local/share/brickadia-launcher'.grey);\n }\n if (l.startsWith('DOWNLOADING')) {\n // TODO: if someone is proactive enough in the future, you could turn these steps into a legitimate progress bar\n /* Here's some launcher log lines that might be helpful\n Grabbing manifest and checking game files...\n DOWNLOADING MANIFEST | Hold on...\n DOWNLOADING MANIFEST (100%) | Hold on...\n DOWNLOADING MANIFEST (100%) | 0 B/s - 13 KiB / 13 KiB (Unknown time remaining...)\n DOWNLOADING MANIFEST (100%) | Done!\n Checking launcher and downloading version info...\n Installing patches and booting...\n DOWNLOADING BRICKADIA (0%) | Done!\n DOWNLOADING BRICKADIA (100%) | 110 MiB/s - 584 MiB / 584 MiB (1 second remaining...)\n DOWNLOADING BRICKADIA (100%) | Nearly done...\n DOWNLOADING BRICKADIA (100%), INSTALLING BRICKADIA (86%) | Nearly done...\n */\n process.stdout.clearLine(0);\n process.stdout.cursorTo(0);\n process.stdout.write(l);\n // add a newline on \"Done!\" but prevent newlines on repeat done messages\n if (l.match(/Done!/) && l !== lastDoneMessage) {\n lastDoneMessage = l;\n process.stdout.write('\\n');\n }\n } else if (l.match(/Disabling core dumps./)) {\n launcherDone = true;\n }\n }\n\n // [2025.07.07-20.45.40:310][845]LogBRWorldManager: World successfully loaded.\n if (\n l.match(\n /^\\[[^\\]]+\\]\\[[^\\]]+\\]LogBRWorldManager: World successfully loaded\\.$/,\n )\n ) {\n info('World successfully loaded.');\n }\n });\n\n // print debug events regardless of debug status\n omegga.on('debug', l => this.log('?>'.magenta, l));\n\n // print chat events as players join/leave the server\n omegga.on('join', (p: OmeggaPlayer) =>\n this.log(\n `${p.displayName.underline} (${p.name.underline}) joined.`.brightBlue,\n ),\n );\n omegga.on('leave', (p: OmeggaPlayer) =>\n this.log(\n `${p.displayName.underline} (${p.name.underline}) left.`.brightBlue,\n ),\n );\n omegga.on('chat', (name, message) => {\n const player = omegga.getPlayer(name);\n this.log(\n `${(player.displayName ?? player.name ?? name).brightYellow.underline}: ${message}`,\n );\n });\n omegga.on('start', () => {\n const wsl = checkWsl();\n log(\n `Server has started${\n wsl === 1 ? ' in single thread mode due to WSL1' : ''\n }. Type ${'/help'.yellow} for more commands`,\n );\n if (!this.omegga.getNextWorld()) {\n info(\n 'No',\n 'default world'.yellow,\n 'is configured. Run',\n '/worlds use <world>'.yellow,\n 'to load one on startup.',\n );\n }\n\n // check if this is WSL2 and wsl2binds is installed\n if (\n wsl === 2 &&\n this.omegga.pluginLoader &&\n !this.omegga.pluginLoader.plugins.some(p => p.getName() === 'wsl2binds')\n ) {\n warn(\n '####'.yellow,\n `You are running ${'WSL2'.yellow} and you don't have the ${\n 'wsl2binds'.yellow\n } plugin.`,\n );\n warn(\n '####'.yellow,\n `The wsl2binds plugin works as a ${\n 'UDP proxy'.underline\n } between Windows and the WSL2 VM.`,\n );\n warn('####'.yellow, 'Install it by:');\n warn('####'.yellow, ' 1. Closing omegga with', '/stop'.green);\n warn(\n '####'.yellow,\n ' 2. Installing wsl2binds with',\n 'omegga install gh:Meshiest/wsl2binds'.green,\n );\n warn('####'.yellow, ' 3. Restarting', 'omegga'.green);\n }\n });\n omegga.on('mapchange', ({ map }) =>\n log('Map changed to', (map.charAt(0).toUpperCase() + map.slice(1)).green),\n );\n omegga.on('unauthorized', () => {\n err('Server failed authentication check');\n info('You can clear auth tokens with', 'omegga auth -gl'.green);\n info(\n 'This will require you to paste a new hosting token or sign-in again',\n );\n process.exit();\n });\n omegga.on('error', e => err('Server caught unhandled exception:\\n' + e));\n omegga.on('server:stopped', () =>\n log('Server has closed. Type', '/stop'.yellow, 'to close omegga'),\n );\n\n this.rl.on('line', this.handleLine.bind(this));\n // Gracefully shut down server on Ctrl+C and SIGTERM\n process.on('SIGINT', () => this.handleLine('/stop'));\n process.on('SIGTERM', () => this.handleLine('/stop'));\n }\n\n async handleLine(line: string) {\n if (line.startsWith('/')) {\n const [cmd, ...args] = line.slice(1).split(' ');\n const c = COMMANDS.find(c => c.aliases.includes(cmd));\n if (!c) {\n err(\n `unrecognized command /${cmd.underline}. Type /help for more info`\n .red,\n );\n } else {\n try {\n const res = c.fn.bind(this)(...args);\n if (res instanceof Promise) await res;\n } catch (e) {\n err('unhandled terminal error', e);\n }\n }\n } else if (line.trim().length > 0) {\n if (this.omegga.started) {\n // broadcast when the chat does not start with a command\n this.omegga.broadcast(\n `\"[<b><color=\\\\\"ff00ff\\\\\">SERVER</></>]: ${sanitize(line)}\"`,\n );\n process.stdout.clearLine(0);\n this.log(`[${'SERVER'.brightMagenta.underline}]: ${line}`);\n\n // if omegga is running a webserver - send this message in the chat log\n if (this.omegga.webserver) {\n const user = { name: 'SERVER', id: '', web: true, color: 'ff00ff' };\n // create database entry, send to web ui\n const chatLog = await this.omegga.webserver.database.addChatLog(\n 'msg',\n user,\n line,\n );\n serverEvents.emit('chat', chatLog);\n }\n } else {\n err(\n 'Server is not started yet. type'.red,\n '/help'.yellow,\n 'for more info'.red,\n );\n }\n }\n }\n\n // let readline render a log without interrupting user input\n log(...args: any[]) {\n process.stdout.clearLine(0);\n process.stdout.cursorTo(0);\n console.log(...Logger.timestamped(args));\n this.rl.prompt(true);\n }\n\n // let readline render a debug log without interrupting user input\n debug(...args: any[]) {\n process.stdout.clearLine(0);\n process.stdout.cursorTo(0);\n console.debug(...Logger.timestamped(args));\n this.rl.prompt(true);\n }\n\n // let readline render a warning log without interrupting user input\n warn(...args: any[]) {\n process.stdout.clearLine(0);\n process.stdout.cursorTo(0);\n console.warn(...Logger.timestamped(args));\n this.rl.prompt(true);\n }\n\n // let readline render an error log without interrupting user input\n error(...args: any[]) {\n process.stdout.clearLine(0);\n process.stdout.cursorTo(0);\n console.error(...Logger.timestamped(args));\n this.rl.prompt(true);\n }\n}\n"],"names":["steamcmdDownloadGame","steamcmdCheckUpdate","plugin","install","world","wsl","checkWsl","c","sanitize","serverEvents","Logger"],"mappings":"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"}
1
+ {"version":3,"file":"terminal.js","sources":["../../src/cli/terminal.ts"],"sourcesContent":["import Logger from '@/logger';\nimport { OmeggaPlayer } from '@/plugin';\nimport { steamcmdCheckUpdate, steamcmdDownloadGame } from '@/updater';\nimport { readBinaryVersion } from '@omegga/matchers/version';\nimport Omegga from '@omegga/server';\nimport { IOmeggaOptions } from '@omegga/types';\nimport { sanitize } from '@util/chat';\nimport { checkWsl } from '@util/wsl';\nimport { serverEvents } from '@webserver/backend/events';\nimport readline from 'readline';\nimport { install } from './plugin';\n\ndeclare global {\n interface String {\n brightRed: string;\n brightGreen: string;\n brightYellow: string;\n brightBlue: string;\n brightMagenta: string;\n brightCyan: string;\n brightWhite: string;\n }\n}\n\nlet log: (...args: any[]) => void,\n err: (...args: any[]) => void,\n warn: (...args: any[]) => void,\n info: (...args: any[]) => void;\n\ntype TerminalCommand = {\n aliases: string[];\n desc: string;\n descLines?: () => string[];\n fn(this: Terminal, ...args: string[]): void | Promise<void>;\n};\n\nfunction gameCommand(\n aliases: string[],\n desc: string,\n usage: string,\n command: string,\n quoteArgs?: boolean,\n): TerminalCommand {\n return {\n aliases,\n desc,\n fn(...args) {\n if (!this.omegga.started) {\n err('The server is not running');\n return;\n }\n if (!args.length) {\n err('usage:', ('/' + aliases[0] + ' ' + usage).yellow);\n return;\n }\n this.omegga.writeln(\n `${command} ${quoteArgs ? '\"' : ''}${args.join(' ')}${\n quoteArgs ? '\"' : ''\n }`,\n );\n this.rl.prompt(true);\n },\n };\n}\n\nconst COMMANDS: TerminalCommand[] = [\n // Brickadia commands\n gameCommand(\n ['kick'],\n 'kick a player',\n '<name|id> [reason]',\n 'Chat.Command /Kick',\n ),\n gameCommand(\n ['ban', 'banish'],\n 'ban a player',\n '<name|id> [time] [reason]',\n 'Ban',\n ),\n gameCommand(\n ['unban', 'pardon'],\n 'unban a player',\n '<name|id>',\n 'Chat.Command /Unban',\n ),\n gameCommand(\n ['grantrole', 'giverole'],\n 'grant a role to a player',\n '<role> <name|id>',\n 'Chat.Command /GrantRole',\n ),\n gameCommand(\n ['revokerole', 'takerole'],\n 'revoke a role from a player',\n '<role> <name|id>',\n 'Chat.Command /RevokeRole',\n ),\n gameCommand(\n ['clearbricks'],\n \"clear a player's bricks\",\n '<name|id>',\n 'Bricks.Clear',\n true,\n ),\n gameCommand(['clearallbricks'], 'clear all bricks', '', 'Bricks.ClearAll'),\n\n // Help command\n {\n aliases: ['help', 'cmds', 'commands'],\n desc: 'list supported commands and their descriptions',\n fn() {\n const maxLen = Math.max(...COMMANDS.map(c => c.aliases[0].length));\n log('Omegga Help Text:\\n');\n log(\n ' Console input not starting with / will be sent in chat from a \"SERVER\" user',\n );\n log(\n ' Console input starting with / will be treated as one of the following commands\\n',\n );\n log(\n '-- Available Omegga commands (type',\n '/command'.yellow.underline,\n 'to run)',\n );\n\n for (const command of COMMANDS.sort((a, b) =>\n a.aliases[0].localeCompare(b.aliases[0]),\n )) {\n const name = command.aliases[0];\n this.log(\n ' ',\n ('/' + name).yellow.underline,\n '-'.padStart(maxLen - name.length + 1),\n command.desc,\n );\n if (command.descLines)\n for (const descLine of command.descLines())\n this.log(' ', ' '.repeat(maxLen + 1), descLine);\n }\n },\n },\n\n // Server controls\n {\n aliases: ['stop', 'exit', 'quit', 'close'],\n desc: 'stop the server and close Omegga',\n async fn() {\n log('Stopping server...');\n await this.omegga.stop();\n process.exit();\n },\n },\n {\n aliases: ['restart'],\n desc: 'trigger a server restart (without announcement or saving)',\n async fn() {\n log('Restarting server...');\n await this.omegga.restartServer();\n },\n },\n {\n aliases: ['version', 'ver'],\n desc: 'print the game version',\n fn() {\n // the running version, and what's actually on disk right now - a steam\n // update can replace the binary underneath a running server\n const running = this.omegga.version;\n const binary = readBinaryVersion(this.omegga.getGameBinaryPath());\n\n if (running > 0) log('Brickadia Server', ('CL' + running).green);\n else warn('Game version is not known yet.');\n\n if (binary == null) return;\n\n if (running > 0 && binary !== running) {\n warn(\n 'Server binary on disk is',\n ('CL' + binary).yellow + '.',\n 'Restart to run the updated build.',\n );\n } else if (!(running > 0)) {\n log('Server binary on disk is', ('CL' + binary).green);\n }\n },\n },\n {\n aliases: ['update'],\n desc: 'try to update the server and restart if started (without announcement or saving',\n async fn() {\n if (!this.omegga.config.__STEAM) {\n err(\n 'This command is only available when the server is installed via SteamCMD',\n );\n return;\n }\n if (this.omegga.stopping || this.omegga.starting) {\n err(\n 'The server is currently starting or stopping. Please wait a moment',\n );\n return;\n }\n const wasStarted = this.omegga.started;\n if (wasStarted) {\n log('Stopping server to update...');\n await this.omegga.stop();\n }\n log('Updating server...');\n try {\n await steamcmdDownloadGame({\n steambeta: this.omegga.config.server?.steambeta,\n steambetaPassword: this.omegga.config.server?.steambetaPassword,\n });\n log('Server updated successfully.');\n } catch (e) {\n err('Error updating server:', e);\n }\n if (wasStarted) {\n log('Starting server...');\n await this.omegga.start();\n }\n },\n },\n {\n aliases: ['updatecheck', 'uc', 'check'],\n desc: 'check for updates. /uc show for details, /uc on|off to toggle auto-update',\n async fn(subcommand?: string) {\n if (!this.omegga.config.__STEAM) {\n err(\n 'This command is only available when the server is installed via SteamCMD',\n );\n return;\n }\n\n const db = this.omegga.webserver?.database;\n\n if (subcommand === 'on' || subcommand === 'off') {\n if (!db) {\n err('Database not available.');\n return;\n }\n const config = await db.getAutoRestartConfig();\n config.autoUpdateEnabled = subcommand === 'on';\n await db.setAutoRestartConfig(config);\n log(\n subcommand === 'on'\n ? 'Auto-update enabled.'.green\n : 'Auto-update disabled.'.yellow,\n );\n return;\n }\n\n log('Checking for updates...');\n const result = steamcmdCheckUpdate(this.omegga.config.server?.steambeta);\n if (!result) {\n err('Failed to check for updates.');\n return;\n }\n const { local, remote, hasUpdate } = result;\n\n if (hasUpdate === true) log('Update available!'.green);\n else if (hasUpdate === false) log('Up to date.'.green);\n else log('Could not determine update status.'.yellow);\n\n if (subcommand === 'show') {\n const branch =\n local.betaKey && local.betaKey !== 'main' ? local.betaKey : 'public';\n const remoteBuild = remote?.branches?.[branch];\n const remotePart = remoteBuild\n ? `BuildID ${remoteBuild.buildid}` +\n (remoteBuild.timeupdated\n ? ` (${new Date(Number(remoteBuild.timeupdated) * 1000).toLocaleString()})`\n : '')\n : 'unknown (private branch?)';\n log(\n [\n ` Local: BuildID ${local.buildId} (${local.installState})`,\n ` Remote: ${remotePart}`,\n ` Branch: ${local.betaKey ?? 'public'}`,\n ].join('\\n'),\n );\n }\n\n if (db) {\n const config = await db.getAutoRestartConfig();\n log(\n config.autoUpdateEnabled\n ? `Auto-update: enabled (every ${config.autoUpdateIntervalMins}m)`\n : 'Auto-update: disabled',\n );\n }\n },\n },\n {\n aliases: ['kill'],\n desc: 'forcefully kill brickadia server process without closing omegga',\n async fn() {\n log('Stopping server...');\n await this.omegga.stop();\n },\n },\n {\n aliases: ['start'],\n desc: 'start the server if it is stopped',\n fn() {\n if (\n !this.omegga ||\n (this.omegga && (this.omegga.starting || this.omegga.started))\n ) {\n err('The server is already running');\n return;\n }\n\n log('Starting server...');\n this.omegga.start();\n },\n },\n {\n aliases: ['cmd'],\n desc: 'run a console command on the Brickadia server. requires /debug for log to show',\n fn(...args) {\n if (!this.omegga.started) {\n err('The server is not running');\n return;\n }\n this.omegga.writeln(args.join(' '));\n },\n },\n {\n aliases: ['debug'],\n desc: 'toggle visibility of brickadia console logs',\n fn() {\n this.options.debug = !this.options.debug;\n log(\n 'Brickadia logs now',\n this.options.debug ? 'visible'.green : 'hidden'.red,\n );\n },\n },\n {\n aliases: ['status'],\n desc: 'display server status information. brick count, online players, etc',\n async fn() {\n if (!this.omegga.started) {\n err('Omegga is not running');\n return;\n }\n const msToTime = (ms: number) => new Date(ms).toISOString().slice(11, 19);\n try {\n const status = await this.omegga.getServerStatus();\n\n log('Server Status');\n this.log(`\n${status.serverName.yellow}\nBricks: ${(status.bricks + '').yellow}\nComponents: ${(status.components + '').yellow}\nUptime: ${msToTime(status.time).yellow}\nPlayers: ${status.players.length === 0 ? 'none'.grey : ''}\n ${status.players\n .map(p => `[${msToTime(p.time).grey}] ${p.name.brightYellow}`)\n .join('\\n ')}\n`);\n } catch (e) {\n err('An error occurred while getting server status');\n }\n },\n },\n\n // plugin stuff\n {\n aliases: ['reload'],\n desc: 'shorthand for /plugins reload',\n async fn() {\n await COMMANDS.find(c => c.aliases.includes('plugins')).fn.bind(this)(\n 'reload',\n );\n },\n },\n {\n aliases: ['plugins', 'plugin', 'p'],\n desc: 'manage Omegga plugins',\n descLines: () => [\n '/plugins install <...plugin names>'.yellow + ' installs plugins',\n '/plugins load <...plugin names>'.yellow +\n ' loads plugins, and enables if they were disabled',\n '/plugins unload <...plugin names>'.yellow + ' unloads plugins',\n '/plugins reload [...plugin names]'.yellow +\n ' reloads all plugins, or those specified',\n '/plugins enable <...plugin names>'.yellow + ' enables plugins',\n '/plugins disable <...plugin names>'.yellow +\n ' disables plugins, and unloads if they were loaded',\n ],\n async fn(subcommand: string, ...args: string[]) {\n if (!this.omegga.pluginLoader) {\n err('Omegga is not using plugins');\n return;\n }\n\n if (!subcommand) {\n const plugins = this.omegga.pluginLoader.plugins;\n if (plugins.length === 0) {\n log('No plugins are installed');\n log(' Install some with', '/plugins install'.yellow.underline);\n } else {\n log('Installed plugins'.yellow.underline);\n for (const plugin of plugins) {\n const name = plugin.getName();\n const docs = plugin.getDocumentation();\n if (plugin.isLoaded()) log(name.cyan.underline + ' (loaded)');\n else if (plugin.isEnabled())\n log(name.green.underline + ' (enabled, not loaded)');\n else log(name.red.underline + ' (disabled)');\n\n log(' ' + docs.description);\n log((' Author: ' + docs.author).gray);\n }\n }\n } else if (subcommand === 'install') {\n // install plugins\n await install(args, { verbose: true });\n log();\n log(\n 'Use',\n '/plugins reload'.yellow,\n 'to reload all plugins and use the installed ones',\n );\n } else if (subcommand === 'load') {\n if (args.length === 0) {\n log('Please specify at least one plugin to load');\n return;\n }\n\n for (const pluginName of args) {\n const plugin = this.omegga.pluginLoader.plugins.find(\n p => p.getName().toLowerCase() === pluginName.toLowerCase(),\n );\n\n if (!plugin) {\n warn('No plugin by the name', pluginName.cyan);\n continue;\n }\n\n const name = plugin.getName();\n if (plugin.isLoaded()) {\n warn(\n name.cyan,\n 'is already loaded, reload with',\n ('/plugins reload ' + name).yellow,\n );\n return;\n }\n\n if (!plugin.isEnabled()) {\n log('Enabling and loading', name.cyan.underline);\n plugin.setEnabled(true);\n await plugin.load();\n } else {\n log('Loading', name.cyan.underline);\n await plugin.load();\n }\n }\n } else if (subcommand === 'unload') {\n if (args.length === 0) {\n log('Please specify at least one plugin to unload');\n return;\n }\n\n for (const pluginName of args) {\n const plugin = this.omegga.pluginLoader.plugins.find(\n p => p.getName().toLowerCase() === pluginName.toLowerCase(),\n );\n\n if (!plugin) {\n warn('No plugin by the name', pluginName.cyan);\n continue;\n }\n\n const name = plugin.getName();\n if (!plugin.isLoaded()) {\n warn(\n name.cyan,\n 'is already unloaded, load with',\n ('/plugins load ' + name).yellow,\n );\n return;\n }\n\n log('Unloading', name.cyan.underline);\n await plugin.unload();\n }\n } else if (subcommand === 'reload') {\n let plugins = (\n args.length === 0\n ? this.omegga.pluginLoader.plugins\n : this.omegga.pluginLoader.plugins.filter(p =>\n args\n .map(a => a.toLowerCase())\n .includes(p.getName().toLowerCase()),\n )\n ).filter(p => p.isEnabled());\n\n const loaded = plugins.filter(p => p.isLoaded());\n log('Unloading', loaded.length, 'plugins');\n for (const plugin of loaded) await plugin.unload();\n\n if (args.length === 0) {\n log('Scanning for new plugins');\n if (!(await this.omegga.pluginLoader.scan())) {\n err('Could not scan for plugins. All plugins are unloaded');\n return;\n }\n }\n\n plugins = (\n args.length === 0\n ? this.omegga.pluginLoader.plugins\n : this.omegga.pluginLoader.plugins.filter(p =>\n args\n .map(a => a.toLowerCase())\n .includes(p.getName().toLowerCase()),\n )\n ).filter(p => p.isEnabled());\n log('Loading', plugins.length, 'plugins');\n for (const plugin of plugins) await plugin.load();\n\n log('Reloaded', plugins.length, 'plugins');\n } else if (subcommand === 'enable') {\n if (args.length === 0) {\n log('Please specify at least one plugin to enable');\n return;\n }\n\n for (const pluginName of args) {\n const plugin = this.omegga.pluginLoader.plugins.find(\n p => p.getName().toLowerCase() === pluginName.toLowerCase(),\n );\n\n if (!plugin) {\n warn('No plugin by the name', pluginName.cyan);\n continue;\n }\n\n const name = plugin.getName();\n if (plugin.isEnabled()) {\n warn(\n name.cyan,\n 'is already enabled, disable with',\n ('/plugins disable ' + name).yellow,\n );\n return;\n }\n\n log(\n 'Enabling',\n name.cyan.underline,\n '(load with',\n ('/plugins load ' + name).yellow + ')',\n );\n plugin.setEnabled(true);\n }\n } else if (subcommand === 'disable') {\n if (args.length === 0) {\n log('Please specify at least one plugin to disable');\n return;\n }\n\n for (const pluginName of args) {\n const plugin = this.omegga.pluginLoader.plugins.find(\n p => p.getName().toLowerCase() === pluginName.toLowerCase(),\n );\n\n if (!plugin) {\n warn('No plugin by the name', pluginName.cyan);\n continue;\n }\n\n const name = plugin.getName();\n if (!plugin.isEnabled()) {\n warn(\n name.cyan,\n 'is already disabled, enable with',\n ('/plugins enable ' + name).yellow,\n );\n return;\n }\n\n if (plugin.isLoaded()) {\n log('Unloading and disabling', name.cyan.underline);\n await plugin.unload();\n plugin.setEnabled(false);\n } else {\n log('Disabling', name.cyan.underline);\n plugin.setEnabled(false);\n }\n }\n }\n },\n },\n {\n aliases: ['world', 'worlds', 'w'],\n desc: 'Manage worlds on the server',\n descLines: () => ['Type /worlds load a world'],\n async fn(subcommand: string, ...args: string[]) {\n switch (subcommand) {\n default:\n const commands = [\n {\n command: '/worlds use [world]',\n desc: 'set or remove a world as the default world for startup',\n short: '/w u [world]',\n },\n {\n command: '/worlds load <world> [rev]',\n desc: 'load a world',\n short: '/w load <world> [rev]',\n },\n {\n command: '/worlds saveas <world>',\n desc: 'save the current world as a new world',\n short: '/w sa <world>',\n },\n {\n command: '/worlds save',\n desc: 'save the current world',\n short: '/w s',\n },\n {\n command: '/worlds revisions <world>',\n desc: 'list revisions of a world',\n short: '/w r <world>',\n },\n {\n command: '/worlds new',\n desc: 'create a new world',\n short: '/w new <name> [Plate|Space|Studio|Peaks]',\n },\n ];\n log(\n 'Default world is',\n this.omegga.getNextWorld()?.file?.yellow || 'none'.grey,\n );\n log('Available world commands:');\n for (const { command, desc, short } of commands) {\n this.log(' ', command.yellow, '-', desc, `(${short.yellow})`);\n }\n return;\n\n case 'use':\n case 'u':\n const world = args[0]?.replace(/\\.brdb$/, '');\n if (world && !this.omegga.worldExists(world)) {\n err(`World \"${world}\" does not exist`);\n return;\n }\n if (this.omegga.setActiveWorld(world || null)) {\n if (world) {\n log(\n `Default world set to ${world.yellow}. It will be loaded next startup.`,\n );\n } else {\n log(\n 'Default world cleared. No world will be loaded on next startup.',\n );\n }\n } else {\n err(`Failed to set default world to ${world.yellow}.`);\n }\n return;\n\n case 'list':\n case 'ls':\n // list worlds\n const worlds = this.omegga.getWorlds();\n if (worlds.length === 0) {\n log(\n 'No worlds found. Create one with',\n '/worlds saveas <world>'.yellow,\n );\n } else {\n log('Available worlds:');\n const prefix = this.omegga.worldPath + '/';\n for (const world of worlds) {\n this.log(\n ' ',\n world.replace(prefix, '').replace(/\\.brdb$/, '').yellow,\n );\n }\n }\n return;\n case 'load':\n case 'l':\n if (!this.omegga.started) {\n err('The server is not running');\n return;\n }\n\n // load a world\n if (args.length === 0) {\n err('Please specify a world to load');\n return;\n }\n const worldName = args[0].replace(/\\.brdb$/, '');\n if (!this.omegga.getWorldPath(worldName)) {\n err(`World \"${worldName}\" does not exist`);\n return;\n }\n let revision: number | undefined;\n if (args.length > 1) {\n revision = parseInt(args[1], 10);\n if (isNaN(revision) || revision < 1) {\n err(`Invalid revision number: ${args[1]}`);\n return;\n }\n }\n let loadRes: boolean = false;\n if (revision) {\n log(`Loading world ${worldName.yellow} at revision ${revision}...`);\n loadRes = await this.omegga.loadWorldRevision(worldName, revision);\n } else {\n log(`Loading world ${worldName.yellow}...`);\n loadRes = await this.omegga.loadWorld(worldName);\n }\n if (loadRes) {\n log(`World ${worldName.yellow} loaded successfully.`);\n } else {\n err(`Failed to load world ${worldName.yellow}`);\n }\n\n return;\n case 'saveas':\n case 'sa':\n if (!this.omegga.started) {\n err('The server is not running');\n return;\n }\n\n // save the current world as a new world\n if (args.length === 0) {\n err('Please specify a world to save as');\n return;\n }\n const saveWorldName = args[0].replace(/\\.brdb$/, '');\n if (this.omegga.getWorldPath(saveWorldName)) {\n err(`World \"${saveWorldName}\" already exists`);\n return;\n }\n log(`Saving current world as ${saveWorldName.yellow}...`);\n const saveAsRes = await this.omegga.saveWorldAs(saveWorldName);\n if (saveAsRes) {\n log(`Current world saved as ${saveWorldName.yellow} successfully.`);\n } else {\n err(`Failed to save current world as ${saveWorldName.yellow}`);\n }\n return;\n\n case 'save':\n case 's':\n if (!this.omegga.started) {\n err('The server is not running');\n return;\n }\n\n // save the current world\n log('Saving current world...');\n const res = await this.omegga.saveWorld();\n if (res) {\n log('Current world saved successfully.');\n } else {\n err('Failed to save the current world');\n }\n return;\n\n case 'revisions':\n case 'r':\n if (!this.omegga.started) {\n err('The server is not running');\n return;\n }\n\n // list revisions of a world\n if (args.length === 0) {\n err('Please specify a world to list revisions for');\n return;\n }\n const revisionsWorldName = args[0].replace(/\\.brdb$/, '');\n if (!this.omegga.getWorldPath(revisionsWorldName)) {\n err(`World \"${revisionsWorldName}\" does not exist`);\n return;\n }\n log(`Listing revisions for world ${revisionsWorldName.yellow}...`);\n try {\n const revisions =\n await this.omegga.getWorldRevisions(revisionsWorldName);\n if (revisions.length === 0) {\n log('No revisions found for world', revisionsWorldName.yellow);\n } else {\n log('Revisions for world', revisionsWorldName.yellow + ':');\n for (const rev of revisions) {\n this.log(\n ' ',\n `Revision ${rev.index.toString().yellow} - ${\n rev.date\n .toISOString()\n .replace('T', ' ')\n .replace('.000Z', '').blue\n }`,\n `(${rev.note})`.grey,\n );\n }\n }\n } catch (e) {\n err(\n 'An error occurred while getting world revisions:',\n e.toString(),\n );\n }\n return;\n\n case 'new':\n case 'n':\n if (!this.omegga.started) {\n err('The server is not running');\n return;\n }\n\n // create a new world\n if (args.length === 0) {\n err('Please specify a name for the new world');\n return;\n }\n const newWorldName = args[0].replace(/\\.brdb$/, '');\n if (this.omegga.getWorldPath(newWorldName)) {\n err(`World \"${newWorldName}\" already exists`);\n return;\n }\n const map = (args[1] ? args[1] : 'Plate') as\n | 'Plate'\n | 'Space'\n | 'Studio'\n | 'Peaks';\n if (!['Plate', 'Space', 'Studio', 'Peaks'].includes(map)) {\n err(`Invalid preset \"${map}\". Valid map are: Plate, Space, Studio`);\n return;\n }\n log(`Creating new world ${newWorldName.yellow}...`);\n this.omegga.createEmptyWorld(newWorldName, map);\n }\n },\n },\n {\n aliases: ['user'],\n desc: 'manage web UI users',\n descLines: () => [\n \"/user passwd <username> - Reset a user's password\",\n '/user resetmfa <username> - Clear TOTP and passkeys',\n ],\n async fn(subcommand?: string, username?: string) {\n const db = this.omegga.webserver?.database;\n if (!db) {\n err('Database not available.');\n return;\n }\n if (!subcommand || !username) {\n err('Usage: /user <passwd|resetmfa> <username>');\n return;\n }\n if (!(await db.userExists(username))) {\n err(`User \"${username}\" does not exist.`);\n return;\n }\n switch (subcommand) {\n case 'passwd': {\n const password = await new Promise<string>(resolve =>\n this.rl.question('New password: ', resolve),\n );\n if (!password) {\n err('Password cannot be empty.');\n return;\n }\n await db.userPasswd(username, password);\n log(`Password updated for \"${username.yellow}\".`);\n break;\n }\n case 'resetmfa': {\n await db.resetUserMfa(username);\n log(\n `MFA cleared for \"${username.yellow}\" (TOTP, passkeys, recovery codes).`,\n );\n break;\n }\n default:\n err(`Unknown subcommand \"${subcommand}\". Use passwd or resetmfa.`);\n }\n },\n },\n];\n\n// the terminal wraps omegga and displays console output and handles console input\nexport default class Terminal {\n options: IOmeggaOptions;\n omegga: Omegga;\n rl: readline.Interface;\n constructor(omegga: Omegga, options: IOmeggaOptions = {}) {\n this.options = options;\n this.omegga = omegga;\n\n // terminal interface\n this.rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n terminal: true,\n });\n this.rl.setPrompt('> '.brightGreen);\n\n // shortand fns\n log = (...args) => this.log('>>'.green, ...args);\n err = (...args) => this.error('!>'.red, ...args);\n info = (...args) => this.log('?>'.blue, ...args);\n warn = (...args) => this.warn('W>'.yellow, ...args);\n\n // print log line if debug is enabled\n let launcherDone = false;\n let lastDoneMessage = '';\n omegga.on('line', l => {\n // Redact the hosting token only in what we print to the debug log.\n // Brickadia echoes its full command line (including -Token=\"...\") via a\n // LogInit line on stdout; restrict the redaction to engine log lines\n // (LogInit/etc.) so we don't mangle other output (e.g. chat) that might\n // legitimately contain a -Token= string. The raw `l` is still delivered\n // to matchers/plugins elsewhere, so this must not mutate that value.\n if (options.debug)\n this.log(\n '::'.blue,\n /^Log\\w+:/.test(l)\n ? l.replace(/-Token=\"[^\"]*\"/, '-Token=\"REDACTED\"')\n : l,\n );\n else if (!launcherDone) {\n if (l.match(/Update Failed/)) {\n err(l);\n info(\n 'This might be resolved by deleting brickadia and reinstalling:',\n );\n info(' rm -rf ~/.local/share/brickadia-launcher'.grey);\n }\n if (l.startsWith('DOWNLOADING')) {\n // TODO: if someone is proactive enough in the future, you could turn these steps into a legitimate progress bar\n /* Here's some launcher log lines that might be helpful\n Grabbing manifest and checking game files...\n DOWNLOADING MANIFEST | Hold on...\n DOWNLOADING MANIFEST (100%) | Hold on...\n DOWNLOADING MANIFEST (100%) | 0 B/s - 13 KiB / 13 KiB (Unknown time remaining...)\n DOWNLOADING MANIFEST (100%) | Done!\n Checking launcher and downloading version info...\n Installing patches and booting...\n DOWNLOADING BRICKADIA (0%) | Done!\n DOWNLOADING BRICKADIA (100%) | 110 MiB/s - 584 MiB / 584 MiB (1 second remaining...)\n DOWNLOADING BRICKADIA (100%) | Nearly done...\n DOWNLOADING BRICKADIA (100%), INSTALLING BRICKADIA (86%) | Nearly done...\n */\n process.stdout.clearLine(0);\n process.stdout.cursorTo(0);\n process.stdout.write(l);\n // add a newline on \"Done!\" but prevent newlines on repeat done messages\n if (l.match(/Done!/) && l !== lastDoneMessage) {\n lastDoneMessage = l;\n process.stdout.write('\\n');\n }\n } else if (l.match(/Disabling core dumps./)) {\n launcherDone = true;\n }\n }\n\n // [2025.07.07-20.45.40:310][845]LogBRWorldManager: World successfully loaded.\n if (\n l.match(\n /^\\[[^\\]]+\\]\\[[^\\]]+\\]LogBRWorldManager: World successfully loaded\\.$/,\n )\n ) {\n info('World successfully loaded.');\n }\n });\n\n // print debug events regardless of debug status\n omegga.on('debug', l => this.log('?>'.magenta, l));\n\n // print chat events as players join/leave the server\n omegga.on('join', (p: OmeggaPlayer) =>\n this.log(\n `${p.displayName.underline} (${p.name.underline}) joined.`.brightBlue,\n ),\n );\n omegga.on('leave', (p: OmeggaPlayer) =>\n this.log(\n `${p.displayName.underline} (${p.name.underline}) left.`.brightBlue,\n ),\n );\n omegga.on('chat', (name, message) => {\n const player = omegga.getPlayer(name);\n this.log(\n `${(player.displayName ?? player.name ?? name).brightYellow.underline}: ${message}`,\n );\n });\n omegga.on('start', () => {\n const wsl = checkWsl();\n log(\n `Server has started${\n wsl === 1 ? ' in single thread mode due to WSL1' : ''\n }. Type ${'/help'.yellow} for more commands`,\n );\n if (!this.omegga.getNextWorld()) {\n info(\n 'No',\n 'default world'.yellow,\n 'is configured. Run',\n '/worlds use <world>'.yellow,\n 'to load one on startup.',\n );\n }\n\n // check if this is WSL2 and wsl2binds is installed\n if (\n wsl === 2 &&\n this.omegga.pluginLoader &&\n !this.omegga.pluginLoader.plugins.some(p => p.getName() === 'wsl2binds')\n ) {\n warn(\n '####'.yellow,\n `You are running ${'WSL2'.yellow} and you don't have the ${\n 'wsl2binds'.yellow\n } plugin.`,\n );\n warn(\n '####'.yellow,\n `The wsl2binds plugin works as a ${\n 'UDP proxy'.underline\n } between Windows and the WSL2 VM.`,\n );\n warn('####'.yellow, 'Install it by:');\n warn('####'.yellow, ' 1. Closing omegga with', '/stop'.green);\n warn(\n '####'.yellow,\n ' 2. Installing wsl2binds with',\n 'omegga install gh:Meshiest/wsl2binds'.green,\n );\n warn('####'.yellow, ' 3. Restarting', 'omegga'.green);\n }\n });\n omegga.on('mapchange', ({ map }) =>\n log('Map changed to', (map.charAt(0).toUpperCase() + map.slice(1)).green),\n );\n omegga.on('unauthorized', () => {\n err('Server failed authentication check');\n info('You can clear auth tokens with', 'omegga auth -gl'.green);\n info(\n 'This will require you to paste a new hosting token or sign-in again',\n );\n process.exit();\n });\n omegga.on('error', e => err('Server caught unhandled exception:\\n' + e));\n omegga.on('server:stopped', () =>\n log('Server has closed. Type', '/stop'.yellow, 'to close omegga'),\n );\n\n this.rl.on('line', this.handleLine.bind(this));\n // Gracefully shut down server on Ctrl+C and SIGTERM\n process.on('SIGINT', () => this.handleLine('/stop'));\n process.on('SIGTERM', () => this.handleLine('/stop'));\n }\n\n async handleLine(line: string) {\n if (line.startsWith('/')) {\n const [cmd, ...args] = line.slice(1).split(' ');\n const c = COMMANDS.find(c => c.aliases.includes(cmd));\n if (!c) {\n err(\n `unrecognized command /${cmd.underline}. Type /help for more info`\n .red,\n );\n } else {\n try {\n const res = c.fn.bind(this)(...args);\n if (res instanceof Promise) await res;\n } catch (e) {\n err('unhandled terminal error', e);\n }\n }\n } else if (line.trim().length > 0) {\n if (this.omegga.started) {\n // broadcast when the chat does not start with a command\n this.omegga.broadcast(\n `\"[<b><color=\\\\\"ff00ff\\\\\">SERVER</></>]: ${sanitize(line)}\"`,\n );\n process.stdout.clearLine(0);\n this.log(`[${'SERVER'.brightMagenta.underline}]: ${line}`);\n\n // if omegga is running a webserver - send this message in the chat log\n if (this.omegga.webserver) {\n const user = { name: 'SERVER', id: '', web: true, color: 'ff00ff' };\n // create database entry, send to web ui\n const chatLog = await this.omegga.webserver.database.addChatLog(\n 'msg',\n user,\n line,\n );\n serverEvents.emit('chat', chatLog);\n }\n } else {\n err(\n 'Server is not started yet. type'.red,\n '/help'.yellow,\n 'for more info'.red,\n );\n }\n }\n }\n\n // let readline render a log without interrupting user input\n log(...args: any[]) {\n process.stdout.clearLine(0);\n process.stdout.cursorTo(0);\n console.log(...Logger.timestamped(args));\n this.rl.prompt(true);\n }\n\n // let readline render a debug log without interrupting user input\n debug(...args: any[]) {\n process.stdout.clearLine(0);\n process.stdout.cursorTo(0);\n console.debug(...Logger.timestamped(args));\n this.rl.prompt(true);\n }\n\n // let readline render a warning log without interrupting user input\n warn(...args: any[]) {\n process.stdout.clearLine(0);\n process.stdout.cursorTo(0);\n console.warn(...Logger.timestamped(args));\n this.rl.prompt(true);\n }\n\n // let readline render an error log without interrupting user input\n error(...args: any[]) {\n process.stdout.clearLine(0);\n process.stdout.cursorTo(0);\n console.error(...Logger.timestamped(args));\n this.rl.prompt(true);\n }\n}\n"],"names":["readBinaryVersion","steamcmdDownloadGame","steamcmdCheckUpdate","plugin","install","world","wsl","checkWsl","c","sanitize","serverEvents","Logger"],"mappings":"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"}
package/dist/main.js CHANGED
@@ -2,6 +2,7 @@
2
2
  const softconfig = require("./softconfig.js");
3
3
  const installer = require("./cli/installer.js");
4
4
  const index = require("./config/index.js");
5
+ const version$1 = require("./omegga/matchers/version.js");
5
6
  const server = require("./omegga/server.js");
6
7
  const file = require("./util/file.js");
7
8
  require("colors");
@@ -191,8 +192,9 @@ const program = commander.description(version.PKG.description).version(version.V
191
192
  }
192
193
  });
193
194
  }
195
+ const gameVersion = version$1.readBinaryVersion(server$1.getGameBinaryPath());
194
196
  logger.default.logp(
195
- `Launching brickadia server on port ${("" + (conf.server.port || 7777)).green}...`
197
+ `Launching Brickadia Server${gameVersion ? " " + ("CL" + gameVersion).green : ""} on port ${("" + (conf.server.port || 7777)).green}...`
196
198
  );
197
199
  logger.default.verbose("Starting Omegga");
198
200
  server$1.start();
package/dist/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sources":["../src/main.ts"],"sourcesContent":["import soft, {\n getOverrideGameBinary,\n getSteamGameDir,\n getSteamInstallDir,\n} from '@/softconfig';\nimport { installLauncher } from '@cli/installer';\nimport * as config from '@config';\nimport Omegga from '@omegga/server';\nimport * as file from '@util/file';\nimport 'colors';\nimport commander from 'commander';\nimport dotenv from 'dotenv';\nimport hasbin from 'hasbin';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport prompts from 'prompts';\nimport updateNotifier from 'update-notifier-cjs';\nimport { auth, config as omeggaConfig, pluginUtil, Terminal } from './cli';\nimport { IConfig } from './config/types';\nimport Logger from './logger';\nimport { GAME_BIN_PATH, STEAMCMD_PATH } from './softconfig';\nimport {\n hasSteamUpdate,\n steamcmdDownloadGame,\n steamcmdDownloadSelf,\n steamcmdInteractiveLogin,\n} from './updater';\nimport { PKG, VERSION } from './version';\n\ndotenv.config({ quiet: true });\n\nconst notifier =\n process.env.PACKAGE_NOTIFIER !== 'false'\n ? updateNotifier({\n pkg: PKG,\n updateCheckInterval: 1000 * 60 * 60 * 24,\n })\n : null;\nnotifier?.notify();\n\n// TODO: let omegga bundle config (roles, bans, server config) to zip\n// TODO: let omegga unbundle config from zip to current omegga dir\n\n// write a default config file\nconst createDefaultConfig = () => {\n Logger.logp('Created default config file');\n config.write(soft.CONFIG_FILENAMES[0] + '.yml', config.defaultConfig);\n file.mkdir(`data/${soft.CONFIG_SAVED_DIR}/Builds`);\n file.mkdir('plugins');\n return config.defaultConfig;\n};\n\nconst program = commander\n .description(PKG.description)\n .version(VERSION)\n .option(\n '-d, --debug',\n 'Print all console logs rather than just chat messages (env: BRICKADIA_DEBUG)',\n )\n .option(\n '-u, --update',\n 'Check for brickadia updates (on steam) and install them if available',\n )\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .action(async () => {\n const { verbose, update } = program.opts();\n // BRICKADIA_DEBUG is an env-var alias for the --debug flag\n const debug = Boolean(program.opts().debug || process.env.BRICKADIA_DEBUG);\n if (program.args.length > 0) {\n program.help();\n process.exit(1);\n }\n Logger.VERBOSE = Boolean(verbose);\n\n // default working directory is the one specified in config\n let workDir = config.store.get('defaultOmegga');\n Logger.verbose('Using working directory', workDir?.yellow);\n\n // if there's a config in the current directory, use that one instead\n if (config.find('.')) workDir = '.';\n\n // check if configured path exists\n if (!fs.existsSync(workDir)) {\n Logger.errorp('configured omegga default path does not exist');\n process.exit(1);\n }\n if (!fs.statSync(workDir).isDirectory) {\n Logger.errorp('configured omegga default path is not a directory');\n process.exit(1);\n }\n\n // find the config for the working directory\n const configFile = config.find(workDir);\n Logger.verbose('Target config file:', configFile?.yellow);\n let conf: IConfig;\n\n // create a default config file if it does not already exist, otherwise load in the existing one\n if (!configFile) {\n Logger.verbose('Creating a new config');\n conf = createDefaultConfig();\n } else {\n Logger.verbose('Reading config file');\n try {\n conf = config.read(configFile);\n } catch (error) {\n Logger.errorp('Error reading config file');\n Logger.verbose(error);\n }\n }\n\n if (conf?.terminal?.timestamp) {\n Logger.setTimestamp(conf.terminal.timestamp);\n }\n\n const overrideBinary = getOverrideGameBinary();\n const isSteam = !conf?.server?.branch;\n if (overrideBinary) {\n if (!fs.existsSync(overrideBinary)) {\n Logger.error(\n 'Binary',\n overrideBinary.yellow,\n 'in',\n 'BRICKADIA_DIR'.yellow,\n 'does not exist!',\n );\n process.exit(1);\n }\n\n Logger.verbose(\n 'Using override binary',\n overrideBinary.yellow,\n '- skipping download.',\n );\n } else if (isSteam) {\n conf.__STEAM = true;\n await setupSteam(conf, update);\n } else {\n Logger.warnp(\n 'Brickadia will be launched with',\n 'non-steam launcher'.yellow,\n );\n Logger.warnp(\n 'New versions of Brickadia are not published on the old launcher.'\n .yellow,\n );\n\n // Check if the local launcher is installed\n if (fs.existsSync(soft.LOCAL_LAUNCHER)) {\n Logger.verbose(\"Using omegga's brickadia-launcher\");\n conf.server.__LOCAL = true;\n } else {\n Logger.verbose(\"Installing launcher as it's missing\");\n await installLauncher();\n }\n }\n\n const globalToken = auth.getGlobalToken();\n\n const hasHostingToken = Boolean(\n conf?.credentials?.token || process.env.BRICKADIA_TOKEN || globalToken,\n );\n\n // Skip auth when the hosting token is present\n if (hasHostingToken) {\n Logger.verbose(\n 'Skipping auth token generation due to host token presence',\n );\n if (conf?.credentials?.token)\n Logger.verbose('Found token in config file');\n else if (process.env.BRICKADIA_TOKEN)\n Logger.verbose('Found token in', 'BRICKADIA_TOKEN'.yellow);\n else if (globalToken)\n Logger.verbose('Found token in omegga global config');\n else Logger.verbose('unreachable - no token found');\n\n // check if the auth files don't exist\n } else if (\n !auth.exists(\n path.join(\n workDir,\n soft.DATA_PATH,\n conf?.server?.savedDir ?? soft.CONFIG_SAVED_DIR,\n conf?.server?.authDir ?? soft.CONFIG_AUTH_DIR,\n ),\n )\n ) {\n const success = await auth.prompt({\n debug,\n email: conf?.credentials?.['email'] ?? process.env.BRICKADIA_USER,\n password: conf?.credentials?.['password'] ?? process.env.BRICKADIA_PASS,\n isSteam,\n branch: conf?.server?.branch,\n authDir: conf?.server?.authDir,\n savedDir: conf?.server?.savedDir,\n launchArgs: conf?.server?.launchArgs,\n });\n if (!success) {\n Logger.errorp('Start aborted - could not generate auth tokens');\n process.exit(1);\n }\n } else {\n Logger.verbose(\n 'Skipping auth token generation due to existing auth files',\n );\n }\n\n // build options\n const options = {\n // default enable web ui (set to false)\n noweb: typeof conf.omegga?.webui === 'boolean' && !conf.omegga?.webui,\n // default enable https (set to true, will not be https if it can't generate)\n https: typeof conf.omegga?.https !== 'boolean' || conf.omegga?.https,\n port: conf.omegga?.port || soft.DEFAULT_PORT,\n debug,\n };\n\n Logger.verbose('Launching with options', options);\n\n // setup the server\n const server = new Omegga(workDir, conf, options);\n Logger.verbose('Created omegga object');\n\n if (verbose) {\n server.on(\n '*',\n (ev: string) => ev !== 'line' && Logger.verbose('EVENT'.green, ev),\n );\n }\n\n // create a terminal\n Logger.setTerminal(new Terminal(server, options));\n\n if (notifier?.update) {\n Logger.logp(\n `Omegga update is available (${('v' + notifier.update.latest).yellow})! Run`,\n 'npm i -g omegga'.yellow,\n 'to update!',\n );\n }\n\n if (\n conf.__STEAM &&\n !update &&\n !conf.server?.steambetaPassword &&\n process.env.STEAM_NOTIFIER !== 'false'\n ) {\n hasSteamUpdate(conf.server?.steambeta).then(hasUpdate => {\n if (hasUpdate) {\n Logger.logp('A server update is available!'.brightBlue);\n Logger.log(\n ' Restart with',\n 'omegga --update'.yellow,\n 'to update every start.',\n );\n Logger.log(' Run', '/update'.yellow, 'to update', 'now'.green + '!');\n } else {\n Logger.verbose('No server updates available.');\n }\n });\n }\n\n Logger.logp(\n `Launching brickadia server on port ${\n ('' + (conf.server.port || 7777)).green\n }...`,\n );\n\n // start the server\n Logger.verbose('Starting Omegga');\n server.start();\n });\n\nprogram\n .command('init')\n .description('Sets up the current directory as a brickadia server')\n .action(async () => {\n const configFile = config.find('.');\n if (configFile) {\n Logger.errorp('Config file already exists:', configFile.yellow.underline);\n process.exit(1);\n }\n createDefaultConfig();\n });\n\nprogram\n .command('steamlogin')\n .description('Interactively log in to Steam (for Steam Guard authentication)')\n .action(async () => {\n if (!process.env.STEAM_USERNAME) {\n Logger.errorp('STEAM_USERNAME environment variable is required.');\n Logger.errorp('Set it in your .env file or environment.');\n process.exit(1);\n }\n\n if (!fs.existsSync(STEAMCMD_PATH)) {\n Logger.errorp(\n 'SteamCMD is not installed. Run',\n 'omegga'.yellow,\n 'first to set it up.',\n );\n process.exit(1);\n }\n\n Logger.logp('Logging in to Steam interactively...');\n const success = await steamcmdInteractiveLogin();\n if (success) {\n Logger.logp('Steam login successful. Credentials are now cached.');\n } else {\n Logger.errorp('Steam login failed.');\n process.exit(1);\n }\n });\n\nprogram\n .command('config [field] [value]')\n .description(\n \"Configure Omegga's default behavior.\\n\" +\n 'Type ' +\n 'omegga config list'.yellow.underline +\n ' for current settings and available fields',\n )\n .action((field, value) => {\n if (!field) field = 'list';\n omeggaConfig(field, value, program.opts());\n });\n\nprogram\n .command('auth')\n .option('-g, --global', 'Remove global auth files')\n .option('-l, --local', 'Remove local auth files')\n .option('-w, --workdir', 'Remove configured location auth files')\n .option('-u, --email <email>', 'User email (must provide password)')\n .option('-p, --pass <password>', 'User password (must provide email)')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description(\n 'Generates server auth tokens from brickadia account email+password',\n )\n .action(\n async ({\n email,\n pass: password,\n local: localAuth,\n workDir,\n global: globalAuth,\n }) => {\n const { verbose } = program.opts();\n // BRICKADIA_DEBUG is an env-var alias for the --debug flag\n const debug = Boolean(\n program.opts().debug || process.env.BRICKADIA_DEBUG,\n );\n Logger.VERBOSE = Boolean(verbose);\n\n let branch: string, authDir: string, savedDir: string, launchArgs: string;\n let isSteam: boolean;\n\n // if there's a config in the current directory, use that one instead\n if (config.find('.')) workDir = '.';\n\n // check if configured path exists\n if (fs.existsSync(workDir) && fs.statSync(workDir).isDirectory) {\n Logger.verbose('Using working directory', workDir.yellow);\n // find the config for the working directory\n const configFile = config.find(workDir);\n Logger.verbose('Target config file:', configFile?.yellow);\n try {\n // read the config and extract the branch\n const conf = config.read(configFile);\n Logger.verbose(\n 'Auth config:',\n conf?.server ?? 'no server config'.grey,\n );\n branch = conf?.server?.branch;\n authDir = conf?.server?.authDir;\n savedDir = conf?.server?.savedDir;\n launchArgs = conf?.server?.launchArgs;\n isSteam = !conf?.server?.branch;\n\n if (localAuth && conf?.credentials?.token) {\n Logger.logp(\n \"This server's auth is managed by the token in\",\n configFile.yellow,\n );\n return;\n }\n } catch (error) {\n Logger.errorp('Error reading config file');\n Logger.verbose(error);\n }\n } else {\n Logger.verbose('Using default working directory', workDir.yellow);\n }\n\n savedDir ??= soft.CONFIG_SAVED_DIR;\n\n const workdirPath = path.join(\n config.store.get('defaultOmegga'),\n `data/${savedDir}/Auth`,\n );\n\n if (globalAuth || localAuth) {\n if (globalAuth) {\n const globalAuthPath = path.join(\n soft.CONFIG_HOME,\n savedDir !== soft.CONFIG_SAVED_DIR ? savedDir : '',\n authDir ?? soft.CONFIG_AUTH_DIR,\n );\n Logger.logp('Clearing auth files from', globalAuthPath.yellow);\n auth.clean(globalAuthPath);\n }\n if (workDir) {\n Logger.logp('Clearing auth files from', workdirPath.yellow);\n await file.rmdir(workdirPath);\n }\n if (localAuth) {\n const localPath = path.resolve(\n `data/${savedDir}/`,\n authDir ?? soft.CONFIG_AUTH_DIR,\n );\n Logger.logp('Clearing auth files from', localPath.yellow);\n await file.rmdir(localPath);\n }\n return;\n }\n\n if (!isSteam) {\n Logger.warnp('Authenticating with', 'non-steam launcher'.yellow);\n }\n\n auth.prompt({\n email,\n password,\n debug,\n branch,\n authDir,\n savedDir,\n launchArgs,\n });\n },\n );\n\nprogram\n .command('info')\n .alias('n')\n .description(\n 'Shows server name, description, port, install info, and installed plugins',\n )\n .action(async () => {\n Logger.errorp('not implemented yet');\n // TODO: implement config parsing\n });\n\nprogram\n .command('install <pluginUrl...>')\n .alias('i')\n .option('-f, --force', 'Forcefully re-install existing plugin') // TODO: implement install --force\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description('Installs a plugin to the current brickadia server')\n .action(async plugins => {\n if (!hasbin.sync('git')) {\n Logger.errorp('git'.yellow, 'must be installed to install plugins.');\n process.exit(1);\n }\n\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { verbose, force } = program.opts();\n Logger.VERBOSE = Boolean(verbose);\n pluginUtil.install(plugins, { verbose, force });\n });\n\nprogram\n .command('update [pluginNames...]')\n .alias('u')\n .option('-f, --force', 'Forcefully re-upgrade existing plugin') // TODO: implement update --force\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description('Updates all or selected installed plugins to latest versions')\n .action(async plugins => {\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { verbose, force } = program.opts();\n Logger.VERBOSE = Boolean(verbose);\n pluginUtil.update(plugins, { verbose, force });\n });\n\nprogram\n .command('check [pluginNames...]')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description('Checks plugins for compatibility issues')\n .action(async plugins => {\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { verbose } = program.opts();\n Logger.VERBOSE = Boolean(verbose);\n pluginUtil.check(plugins, { verbose });\n });\n\nprogram\n .command('init-plugin')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description('Initializes a new plugin with the given name and settings')\n .action(async () => {\n const { verbose } = program.opts();\n Logger.VERBOSE = Boolean(verbose);\n\n pluginUtil.init();\n });\n\nprogram\n .command('plugin-init')\n .description('Alias for ' + 'init-plugin'.yellow.underline)\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .action(async () => {\n const { verbose } = program.opts();\n Logger.VERBOSE = Boolean(verbose);\n\n pluginUtil.init();\n });\n\nprogram\n .command('get-config <pluginName> [configName]')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .option('-j, --json', 'Print config as json')\n .description(\n 'Gets a config for a plugin. If ' +\n 'configName'.yellow.underline +\n ' is omitted, returns all config values.',\n )\n .action(async (pluginName, configName) => {\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { verbose } = program.opts();\n const json = program.args.includes('-j') || program.args.includes('--json');\n Logger.VERBOSE = Boolean(verbose);\n if (!configName) {\n pluginUtil.listConfig(pluginName, json);\n } else {\n pluginUtil.getConfig(pluginName, configName, json);\n }\n });\n\nprogram\n .command('set-config <pluginName> [configName] [configValue]')\n .option('-y, --yes', 'Skip confirmation prompt')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description(\n 'Sets a config for a plugin. If ' +\n 'configValue'.yellow.underline +\n ' is omitted, the config will be reset. If ' +\n 'configName'.yellow.underline +\n ' is omitted, the entire plugin config will be reset.',\n )\n .action(async (pluginName, configName, configValue) => {\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { verbose } = program.opts();\n const yes = program.args.includes('-y') || program.args.includes('--yes');\n Logger.VERBOSE = Boolean(verbose);\n if (!configName) {\n pluginUtil.resetAllConfigs(pluginName, yes);\n } else if (!configValue) {\n pluginUtil.resetConfig(pluginName, configName);\n } else {\n pluginUtil.setConfig(pluginName, configName, configValue);\n }\n });\n\nprogram.parseAsync(process.argv);\n\nasync function setupSteam(config: config.IConfig, forceUpdate = false) {\n const steambeta = config?.server?.steambeta;\n const steambetaPassword = config?.server?.steambetaPassword;\n\n const binaryPath = path.join(\n getSteamInstallDir(), // steam install directory\n steambeta ?? 'main', // steam beta branch (or main)\n getSteamGameDir(), // Brickadia\n GAME_BIN_PATH, // path to binary\n );\n\n if (!forceUpdate && fs.existsSync(binaryPath)) {\n Logger.verbose(\n 'Game binary already exists at',\n binaryPath.yellow,\n '- skipping download.',\n );\n return;\n }\n\n // Check if steamcmd is installed\n if (!fs.existsSync(STEAMCMD_PATH)) {\n // Lookup steamcmd in path\n const hasSteamcmd = hasbin.sync('steamcmd');\n\n if (!hasSteamcmd) {\n // Prompt to install steamcmd\n const { install } =\n process.env.SKIP_STEAMCMD_PROMPT === 'true'\n ? { install: true }\n : await prompts({\n type: 'confirm',\n name: 'install',\n message: 'SteamCMD is not installed. OK to download it?',\n initial: true,\n });\n\n if (!install) {\n Logger.errorp('SteamCMD is required for steam support. Exiting...');\n process.exit(1);\n }\n\n Logger.logp('Downloading SteamCMD...');\n }\n\n try {\n steamcmdDownloadSelf();\n if (!fs.existsSync(STEAMCMD_PATH)) {\n Logger.errorp('Failed to setup SteamCMD. Exiting...');\n process.exit(1);\n }\n } catch (err) {\n Logger.errorp('Error setting up SteamCMD:', err);\n process.exit(1);\n }\n }\n\n Logger.logp('Downloading Brickadia', (steambeta ?? 'main').yellow, '...');\n try {\n await steamcmdDownloadGame({ steambeta, steambetaPassword });\n } catch (err) {\n Logger.errorp('Error downloading Brickadia:', err);\n process.exit(1);\n }\n}\n"],"names":["PKG","Logger","config.write","soft","config.defaultConfig","file.mkdir","VERSION","config.store","config.find","config.read","getOverrideGameBinary","installLauncher","auth","server","Omegga","Terminal","hasSteamUpdate","STEAMCMD_PATH","steamcmdInteractiveLogin","omeggaConfig","file.rmdir","pluginUtil","config","getSteamInstallDir","getSteamGameDir","GAME_BIN_PATH","steamcmdDownloadSelf","steamcmdDownloadGame"],"mappings":"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"}
1
+ {"version":3,"file":"main.js","sources":["../src/main.ts"],"sourcesContent":["import soft, {\n getOverrideGameBinary,\n getSteamGameDir,\n getSteamInstallDir,\n} from '@/softconfig';\nimport { installLauncher } from '@cli/installer';\nimport * as config from '@config';\nimport { readBinaryVersion } from '@omegga/matchers/version';\nimport Omegga from '@omegga/server';\nimport * as file from '@util/file';\nimport 'colors';\nimport commander from 'commander';\nimport dotenv from 'dotenv';\nimport hasbin from 'hasbin';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport prompts from 'prompts';\nimport updateNotifier from 'update-notifier-cjs';\nimport { auth, config as omeggaConfig, pluginUtil, Terminal } from './cli';\nimport { IConfig } from './config/types';\nimport Logger from './logger';\nimport { GAME_BIN_PATH, STEAMCMD_PATH } from './softconfig';\nimport {\n hasSteamUpdate,\n steamcmdDownloadGame,\n steamcmdDownloadSelf,\n steamcmdInteractiveLogin,\n} from './updater';\nimport { PKG, VERSION } from './version';\n\ndotenv.config({ quiet: true });\n\nconst notifier =\n process.env.PACKAGE_NOTIFIER !== 'false'\n ? updateNotifier({\n pkg: PKG,\n updateCheckInterval: 1000 * 60 * 60 * 24,\n })\n : null;\nnotifier?.notify();\n\n// TODO: let omegga bundle config (roles, bans, server config) to zip\n// TODO: let omegga unbundle config from zip to current omegga dir\n\n// write a default config file\nconst createDefaultConfig = () => {\n Logger.logp('Created default config file');\n config.write(soft.CONFIG_FILENAMES[0] + '.yml', config.defaultConfig);\n file.mkdir(`data/${soft.CONFIG_SAVED_DIR}/Builds`);\n file.mkdir('plugins');\n return config.defaultConfig;\n};\n\nconst program = commander\n .description(PKG.description)\n .version(VERSION)\n .option(\n '-d, --debug',\n 'Print all console logs rather than just chat messages (env: BRICKADIA_DEBUG)',\n )\n .option(\n '-u, --update',\n 'Check for brickadia updates (on steam) and install them if available',\n )\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .action(async () => {\n const { verbose, update } = program.opts();\n // BRICKADIA_DEBUG is an env-var alias for the --debug flag\n const debug = Boolean(program.opts().debug || process.env.BRICKADIA_DEBUG);\n if (program.args.length > 0) {\n program.help();\n process.exit(1);\n }\n Logger.VERBOSE = Boolean(verbose);\n\n // default working directory is the one specified in config\n let workDir = config.store.get('defaultOmegga');\n Logger.verbose('Using working directory', workDir?.yellow);\n\n // if there's a config in the current directory, use that one instead\n if (config.find('.')) workDir = '.';\n\n // check if configured path exists\n if (!fs.existsSync(workDir)) {\n Logger.errorp('configured omegga default path does not exist');\n process.exit(1);\n }\n if (!fs.statSync(workDir).isDirectory) {\n Logger.errorp('configured omegga default path is not a directory');\n process.exit(1);\n }\n\n // find the config for the working directory\n const configFile = config.find(workDir);\n Logger.verbose('Target config file:', configFile?.yellow);\n let conf: IConfig;\n\n // create a default config file if it does not already exist, otherwise load in the existing one\n if (!configFile) {\n Logger.verbose('Creating a new config');\n conf = createDefaultConfig();\n } else {\n Logger.verbose('Reading config file');\n try {\n conf = config.read(configFile);\n } catch (error) {\n Logger.errorp('Error reading config file');\n Logger.verbose(error);\n }\n }\n\n if (conf?.terminal?.timestamp) {\n Logger.setTimestamp(conf.terminal.timestamp);\n }\n\n const overrideBinary = getOverrideGameBinary();\n const isSteam = !conf?.server?.branch;\n if (overrideBinary) {\n if (!fs.existsSync(overrideBinary)) {\n Logger.error(\n 'Binary',\n overrideBinary.yellow,\n 'in',\n 'BRICKADIA_DIR'.yellow,\n 'does not exist!',\n );\n process.exit(1);\n }\n\n Logger.verbose(\n 'Using override binary',\n overrideBinary.yellow,\n '- skipping download.',\n );\n } else if (isSteam) {\n conf.__STEAM = true;\n await setupSteam(conf, update);\n } else {\n Logger.warnp(\n 'Brickadia will be launched with',\n 'non-steam launcher'.yellow,\n );\n Logger.warnp(\n 'New versions of Brickadia are not published on the old launcher.'\n .yellow,\n );\n\n // Check if the local launcher is installed\n if (fs.existsSync(soft.LOCAL_LAUNCHER)) {\n Logger.verbose(\"Using omegga's brickadia-launcher\");\n conf.server.__LOCAL = true;\n } else {\n Logger.verbose(\"Installing launcher as it's missing\");\n await installLauncher();\n }\n }\n\n const globalToken = auth.getGlobalToken();\n\n const hasHostingToken = Boolean(\n conf?.credentials?.token || process.env.BRICKADIA_TOKEN || globalToken,\n );\n\n // Skip auth when the hosting token is present\n if (hasHostingToken) {\n Logger.verbose(\n 'Skipping auth token generation due to host token presence',\n );\n if (conf?.credentials?.token)\n Logger.verbose('Found token in config file');\n else if (process.env.BRICKADIA_TOKEN)\n Logger.verbose('Found token in', 'BRICKADIA_TOKEN'.yellow);\n else if (globalToken)\n Logger.verbose('Found token in omegga global config');\n else Logger.verbose('unreachable - no token found');\n\n // check if the auth files don't exist\n } else if (\n !auth.exists(\n path.join(\n workDir,\n soft.DATA_PATH,\n conf?.server?.savedDir ?? soft.CONFIG_SAVED_DIR,\n conf?.server?.authDir ?? soft.CONFIG_AUTH_DIR,\n ),\n )\n ) {\n const success = await auth.prompt({\n debug,\n email: conf?.credentials?.['email'] ?? process.env.BRICKADIA_USER,\n password: conf?.credentials?.['password'] ?? process.env.BRICKADIA_PASS,\n isSteam,\n branch: conf?.server?.branch,\n authDir: conf?.server?.authDir,\n savedDir: conf?.server?.savedDir,\n launchArgs: conf?.server?.launchArgs,\n });\n if (!success) {\n Logger.errorp('Start aborted - could not generate auth tokens');\n process.exit(1);\n }\n } else {\n Logger.verbose(\n 'Skipping auth token generation due to existing auth files',\n );\n }\n\n // build options\n const options = {\n // default enable web ui (set to false)\n noweb: typeof conf.omegga?.webui === 'boolean' && !conf.omegga?.webui,\n // default enable https (set to true, will not be https if it can't generate)\n https: typeof conf.omegga?.https !== 'boolean' || conf.omegga?.https,\n port: conf.omegga?.port || soft.DEFAULT_PORT,\n debug,\n };\n\n Logger.verbose('Launching with options', options);\n\n // setup the server\n const server = new Omegga(workDir, conf, options);\n Logger.verbose('Created omegga object');\n\n if (verbose) {\n server.on(\n '*',\n (ev: string) => ev !== 'line' && Logger.verbose('EVENT'.green, ev),\n );\n }\n\n // create a terminal\n Logger.setTerminal(new Terminal(server, options));\n\n if (notifier?.update) {\n Logger.logp(\n `Omegga update is available (${('v' + notifier.update.latest).yellow})! Run`,\n 'npm i -g omegga'.yellow,\n 'to update!',\n );\n }\n\n if (\n conf.__STEAM &&\n !update &&\n !conf.server?.steambetaPassword &&\n process.env.STEAM_NOTIFIER !== 'false'\n ) {\n hasSteamUpdate(conf.server?.steambeta).then(hasUpdate => {\n if (hasUpdate) {\n Logger.logp('A server update is available!'.brightBlue);\n Logger.log(\n ' Restart with',\n 'omegga --update'.yellow,\n 'to update every start.',\n );\n Logger.log(' Run', '/update'.yellow, 'to update', 'now'.green + '!');\n } else {\n Logger.verbose('No server updates available.');\n }\n });\n }\n\n // resolved from the binary, so it's available before the server starts\n const gameVersion = readBinaryVersion(server.getGameBinaryPath());\n\n Logger.logp(\n `Launching Brickadia Server${\n gameVersion ? ' ' + ('CL' + gameVersion).green : ''\n } on port ${('' + (conf.server.port || 7777)).green}...`,\n );\n\n // start the server\n Logger.verbose('Starting Omegga');\n server.start();\n });\n\nprogram\n .command('init')\n .description('Sets up the current directory as a brickadia server')\n .action(async () => {\n const configFile = config.find('.');\n if (configFile) {\n Logger.errorp('Config file already exists:', configFile.yellow.underline);\n process.exit(1);\n }\n createDefaultConfig();\n });\n\nprogram\n .command('steamlogin')\n .description('Interactively log in to Steam (for Steam Guard authentication)')\n .action(async () => {\n if (!process.env.STEAM_USERNAME) {\n Logger.errorp('STEAM_USERNAME environment variable is required.');\n Logger.errorp('Set it in your .env file or environment.');\n process.exit(1);\n }\n\n if (!fs.existsSync(STEAMCMD_PATH)) {\n Logger.errorp(\n 'SteamCMD is not installed. Run',\n 'omegga'.yellow,\n 'first to set it up.',\n );\n process.exit(1);\n }\n\n Logger.logp('Logging in to Steam interactively...');\n const success = await steamcmdInteractiveLogin();\n if (success) {\n Logger.logp('Steam login successful. Credentials are now cached.');\n } else {\n Logger.errorp('Steam login failed.');\n process.exit(1);\n }\n });\n\nprogram\n .command('config [field] [value]')\n .description(\n \"Configure Omegga's default behavior.\\n\" +\n 'Type ' +\n 'omegga config list'.yellow.underline +\n ' for current settings and available fields',\n )\n .action((field, value) => {\n if (!field) field = 'list';\n omeggaConfig(field, value, program.opts());\n });\n\nprogram\n .command('auth')\n .option('-g, --global', 'Remove global auth files')\n .option('-l, --local', 'Remove local auth files')\n .option('-w, --workdir', 'Remove configured location auth files')\n .option('-u, --email <email>', 'User email (must provide password)')\n .option('-p, --pass <password>', 'User password (must provide email)')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description(\n 'Generates server auth tokens from brickadia account email+password',\n )\n .action(\n async ({\n email,\n pass: password,\n local: localAuth,\n workDir,\n global: globalAuth,\n }) => {\n const { verbose } = program.opts();\n // BRICKADIA_DEBUG is an env-var alias for the --debug flag\n const debug = Boolean(\n program.opts().debug || process.env.BRICKADIA_DEBUG,\n );\n Logger.VERBOSE = Boolean(verbose);\n\n let branch: string, authDir: string, savedDir: string, launchArgs: string;\n let isSteam: boolean;\n\n // if there's a config in the current directory, use that one instead\n if (config.find('.')) workDir = '.';\n\n // check if configured path exists\n if (fs.existsSync(workDir) && fs.statSync(workDir).isDirectory) {\n Logger.verbose('Using working directory', workDir.yellow);\n // find the config for the working directory\n const configFile = config.find(workDir);\n Logger.verbose('Target config file:', configFile?.yellow);\n try {\n // read the config and extract the branch\n const conf = config.read(configFile);\n Logger.verbose(\n 'Auth config:',\n conf?.server ?? 'no server config'.grey,\n );\n branch = conf?.server?.branch;\n authDir = conf?.server?.authDir;\n savedDir = conf?.server?.savedDir;\n launchArgs = conf?.server?.launchArgs;\n isSteam = !conf?.server?.branch;\n\n if (localAuth && conf?.credentials?.token) {\n Logger.logp(\n \"This server's auth is managed by the token in\",\n configFile.yellow,\n );\n return;\n }\n } catch (error) {\n Logger.errorp('Error reading config file');\n Logger.verbose(error);\n }\n } else {\n Logger.verbose('Using default working directory', workDir.yellow);\n }\n\n savedDir ??= soft.CONFIG_SAVED_DIR;\n\n const workdirPath = path.join(\n config.store.get('defaultOmegga'),\n `data/${savedDir}/Auth`,\n );\n\n if (globalAuth || localAuth) {\n if (globalAuth) {\n const globalAuthPath = path.join(\n soft.CONFIG_HOME,\n savedDir !== soft.CONFIG_SAVED_DIR ? savedDir : '',\n authDir ?? soft.CONFIG_AUTH_DIR,\n );\n Logger.logp('Clearing auth files from', globalAuthPath.yellow);\n auth.clean(globalAuthPath);\n }\n if (workDir) {\n Logger.logp('Clearing auth files from', workdirPath.yellow);\n await file.rmdir(workdirPath);\n }\n if (localAuth) {\n const localPath = path.resolve(\n `data/${savedDir}/`,\n authDir ?? soft.CONFIG_AUTH_DIR,\n );\n Logger.logp('Clearing auth files from', localPath.yellow);\n await file.rmdir(localPath);\n }\n return;\n }\n\n if (!isSteam) {\n Logger.warnp('Authenticating with', 'non-steam launcher'.yellow);\n }\n\n auth.prompt({\n email,\n password,\n debug,\n branch,\n authDir,\n savedDir,\n launchArgs,\n });\n },\n );\n\nprogram\n .command('info')\n .alias('n')\n .description(\n 'Shows server name, description, port, install info, and installed plugins',\n )\n .action(async () => {\n Logger.errorp('not implemented yet');\n // TODO: implement config parsing\n });\n\nprogram\n .command('install <pluginUrl...>')\n .alias('i')\n .option('-f, --force', 'Forcefully re-install existing plugin') // TODO: implement install --force\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description('Installs a plugin to the current brickadia server')\n .action(async plugins => {\n if (!hasbin.sync('git')) {\n Logger.errorp('git'.yellow, 'must be installed to install plugins.');\n process.exit(1);\n }\n\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { verbose, force } = program.opts();\n Logger.VERBOSE = Boolean(verbose);\n pluginUtil.install(plugins, { verbose, force });\n });\n\nprogram\n .command('update [pluginNames...]')\n .alias('u')\n .option('-f, --force', 'Forcefully re-upgrade existing plugin') // TODO: implement update --force\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description('Updates all or selected installed plugins to latest versions')\n .action(async plugins => {\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { verbose, force } = program.opts();\n Logger.VERBOSE = Boolean(verbose);\n pluginUtil.update(plugins, { verbose, force });\n });\n\nprogram\n .command('check [pluginNames...]')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description('Checks plugins for compatibility issues')\n .action(async plugins => {\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { verbose } = program.opts();\n Logger.VERBOSE = Boolean(verbose);\n pluginUtil.check(plugins, { verbose });\n });\n\nprogram\n .command('init-plugin')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description('Initializes a new plugin with the given name and settings')\n .action(async () => {\n const { verbose } = program.opts();\n Logger.VERBOSE = Boolean(verbose);\n\n pluginUtil.init();\n });\n\nprogram\n .command('plugin-init')\n .description('Alias for ' + 'init-plugin'.yellow.underline)\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .action(async () => {\n const { verbose } = program.opts();\n Logger.VERBOSE = Boolean(verbose);\n\n pluginUtil.init();\n });\n\nprogram\n .command('get-config <pluginName> [configName]')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .option('-j, --json', 'Print config as json')\n .description(\n 'Gets a config for a plugin. If ' +\n 'configName'.yellow.underline +\n ' is omitted, returns all config values.',\n )\n .action(async (pluginName, configName) => {\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { verbose } = program.opts();\n const json = program.args.includes('-j') || program.args.includes('--json');\n Logger.VERBOSE = Boolean(verbose);\n if (!configName) {\n pluginUtil.listConfig(pluginName, json);\n } else {\n pluginUtil.getConfig(pluginName, configName, json);\n }\n });\n\nprogram\n .command('set-config <pluginName> [configName] [configValue]')\n .option('-y, --yes', 'Skip confirmation prompt')\n .option('-v, --verbose', 'Print extra messages for debugging purposes')\n .description(\n 'Sets a config for a plugin. If ' +\n 'configValue'.yellow.underline +\n ' is omitted, the config will be reset. If ' +\n 'configName'.yellow.underline +\n ' is omitted, the entire plugin config will be reset.',\n )\n .action(async (pluginName, configName, configValue) => {\n if (!config.find('.')) {\n Logger.errorp(\n 'Not an omegga directory, run ',\n 'omegga init'.yellow,\n 'to setup one.',\n );\n process.exit(1);\n }\n const { verbose } = program.opts();\n const yes = program.args.includes('-y') || program.args.includes('--yes');\n Logger.VERBOSE = Boolean(verbose);\n if (!configName) {\n pluginUtil.resetAllConfigs(pluginName, yes);\n } else if (!configValue) {\n pluginUtil.resetConfig(pluginName, configName);\n } else {\n pluginUtil.setConfig(pluginName, configName, configValue);\n }\n });\n\nprogram.parseAsync(process.argv);\n\nasync function setupSteam(config: config.IConfig, forceUpdate = false) {\n const steambeta = config?.server?.steambeta;\n const steambetaPassword = config?.server?.steambetaPassword;\n\n const binaryPath = path.join(\n getSteamInstallDir(), // steam install directory\n steambeta ?? 'main', // steam beta branch (or main)\n getSteamGameDir(), // Brickadia\n GAME_BIN_PATH, // path to binary\n );\n\n if (!forceUpdate && fs.existsSync(binaryPath)) {\n Logger.verbose(\n 'Game binary already exists at',\n binaryPath.yellow,\n '- skipping download.',\n );\n return;\n }\n\n // Check if steamcmd is installed\n if (!fs.existsSync(STEAMCMD_PATH)) {\n // Lookup steamcmd in path\n const hasSteamcmd = hasbin.sync('steamcmd');\n\n if (!hasSteamcmd) {\n // Prompt to install steamcmd\n const { install } =\n process.env.SKIP_STEAMCMD_PROMPT === 'true'\n ? { install: true }\n : await prompts({\n type: 'confirm',\n name: 'install',\n message: 'SteamCMD is not installed. OK to download it?',\n initial: true,\n });\n\n if (!install) {\n Logger.errorp('SteamCMD is required for steam support. Exiting...');\n process.exit(1);\n }\n\n Logger.logp('Downloading SteamCMD...');\n }\n\n try {\n steamcmdDownloadSelf();\n if (!fs.existsSync(STEAMCMD_PATH)) {\n Logger.errorp('Failed to setup SteamCMD. Exiting...');\n process.exit(1);\n }\n } catch (err) {\n Logger.errorp('Error setting up SteamCMD:', err);\n process.exit(1);\n }\n }\n\n Logger.logp('Downloading Brickadia', (steambeta ?? 'main').yellow, '...');\n try {\n await steamcmdDownloadGame({ steambeta, steambetaPassword });\n } catch (err) {\n Logger.errorp('Error downloading Brickadia:', err);\n process.exit(1);\n }\n}\n"],"names":["PKG","Logger","config.write","soft","config.defaultConfig","file.mkdir","VERSION","config.store","config.find","config.read","getOverrideGameBinary","installLauncher","auth","server","Omegga","Terminal","hasSteamUpdate","readBinaryVersion","STEAMCMD_PATH","steamcmdInteractiveLogin","omeggaConfig","file.rmdir","pluginUtil","config","getSteamInstallDir","getSteamGameDir","GAME_BIN_PATH","steamcmdDownloadSelf","steamcmdDownloadGame"],"mappings":"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"}
@@ -319,12 +319,11 @@ class Omegga extends wrapper.default {
319
319
  //
320
320
  async start() {
321
321
  this.starting = true;
322
- if (this.version < 0) {
323
- const binVersion = version$1.readBinaryVersion(this.getGameBinaryPath());
324
- if (binVersion != null) {
325
- this.version = binVersion;
326
- logger.default.verbose("Brickadia Version (from binary)", binVersion);
327
- }
322
+ const binVersion = version$1.readBinaryVersion(this.getGameBinaryPath());
323
+ this.version = binVersion ?? -1;
324
+ if (binVersion != null) {
325
+ logger.default.verbose("Brickadia Version (from binary)", binVersion);
326
+ this.emit("version", binVersion);
328
327
  }
329
328
  if (this.webserver) await this.webserver.start();
330
329
  if (this.pluginLoader) {
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sources":["../../src/omegga/server.ts"],"sourcesContent":["import Logger from '@/logger';\nimport { OmeggaLike, OmeggaPlayer, PluginInterop } from '@/plugin';\nimport {\n BRICKADIA_AUTH_FILES,\n CONFIG_AUTH_DIR,\n CONFIG_HOME,\n CONFIG_SAVED_DIR,\n DATA_PATH,\n} from '@/softconfig';\nimport { VERSION } from '@/version';\nimport { EnvironmentPreset } from '@brickadia/presets';\nimport {\n BRBanList,\n BRPlayerNameCache,\n BRRoleAssignments,\n BRRoleSetup,\n} from '@brickadia/types';\nimport { IConfig } from '@config/types';\nimport { map as mapUtils, pattern, uuid } from '@util';\nimport { readBrdbRevisions } from '@util/brdb';\nimport { copyFiles, mkdir, readWatchedJSON } from '@util/file';\nimport Webserver from '@webserver/backend';\nimport brs, {\n WorldReader,\n writeBrzLegacy,\n type ReadSaveObject,\n type WriteSaveObject,\n} from 'brs-js';\nimport 'colors';\nimport glob from 'glob';\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { basename, join, resolve, sep } from 'path';\nimport { AutoRestartConfig } from '..';\nimport commandInjector from './commandInjector';\nimport {\n ConsoleCommands,\n EA2_VERSION,\n PREFAB_VERSION,\n resolveConsoleCommands,\n} from './commands';\nimport MATCHERS from './matchers';\nimport { readBinaryVersion } from './matchers/version';\nimport Player from './player';\nimport { PluginLoader } from './plugin';\nimport {\n IGamemode,\n ILogMinigame,\n IMinigameList,\n IOmeggaOptions,\n IPlayerPositions,\n IServerStatus,\n} from './types';\nimport OmeggaWrapper from './wrapper';\n\nconst MISSING_CMD =\n '\"Command not found. Type <color=\\\\\"ffff00\\\\\">/help</> for a list of commands or <color=\\\\\"ffff00\\\\\">/plugins</> for plugin information.\"';\n\n// Prefab.SaveRegion requires a region; when saving the whole world we pass a\n// maximal extent centered on the origin to capture everything.\nconst WHOLE_WORLD_EXTENT = 1_000_000_000;\n\n// These helpers are module-level (not class methods) on purpose: safe plugins\n// call these methods through a ProxyOmegga whose prototype steals Omegga's\n// implementations (see injectOmeggaPrototypes). A `#private` method would fail\n// the brand check when `this` is a ProxyOmegga (\"Receiver must be an instance\n// of class Omegga\"), so anything a stolen method depends on must not be\n// `#private`. Module functions keep working regardless of the receiver.\n\n/**\n * Whether the running game version has removed the legacy .brs bricks console\n * commands (Bricks.Save/Load/ClearAll/ClearRegion, World.LoadAdditive) in\n * favor of the prefab (`br.Prefab.*`) and world (`br.World.Clear*`) commands.\n * Removed at Brickadia CL{@link PREFAB_VERSION}.\n */\nfunction brsRemoved(version: number): boolean {\n return version > 0 && version >= PREFAB_VERSION;\n}\n\n/**\n * Warn that a method backed by a removed console command is a no-op on the\n * running game version, and return whether the caller should bail.\n * @param version the running game version\n * @param method the omegga method being called (for the message)\n * @param since CL version the underlying command was removed at\n * @param release human release name for that version (e.g. `EA2`, `EA3`)\n * @param replacement suggested replacement method/API\n */\nfunction warnRemoved(\n version: number,\n method: string,\n since: number,\n release: string,\n replacement: string,\n): boolean {\n if (!(version > 0 && version >= since)) return false;\n Logger.warnp(\n `omegga.${method}() uses a console command removed in Brickadia ` +\n `${release}. This call has no effect - use ${replacement} instead.`,\n );\n return true;\n}\n\n/**\n * Resolve `name` to an existing file inside `dir`, appending `ext` when it is\n * missing. `name` may be a bare name, a relative path, or an absolute path --\n * `resolve` (unlike `join`) lets callers pass an absolute path from one of\n * these getters straight back into an api that takes a name.\n * @returns the absolute path, or undefined if it does not exist or escapes `dir`\n */\nexport function resolveInDir(\n dir: string,\n name: string,\n ext: string,\n): string | undefined {\n if (typeof name !== 'string' || !name) return undefined;\n const file = resolve(\n dir,\n name.toLowerCase().endsWith(ext) ? name : name + ext,\n );\n // keep the file inside dir (guards against `..` traversal)\n if (!file.startsWith(dir.endsWith(sep) ? dir : dir + sep)) return undefined;\n return existsSync(file) ? file : undefined;\n}\n\n/**\n * Read a `.brz` prefab file (EA3) into a legacy save object. Brick geometry,\n * ownership, assets, materials, and components are reconstructed; wires are\n * not (the save-level `wires` array is left empty). Component names/data are\n * EA3-native (e.g. `Component_Internal_Seat`), not the legacy `BCD_*` names.\n *\n * This is a plain function rather than a method because `readSaveData` and\n * `getSaveData` are handed to safe plugins via STEAL_PROTOTYPES and run with\n * `this` bound to the plugin's proxy omegga, which has no private methods on\n * it -- calling `this.readPrefabData(...)` there throws \"not a function\".\n */\nfunction readPrefabData(\n omegga: {\n version: number;\n currentMap?: string;\n host?: { id: string; name: string };\n },\n file: string,\n { nobricks = false } = {},\n): ReadSaveObject {\n // gridId 1 is the world's main brick grid (MAIN_GRID); entity sub-grids\n // (>=2) are not captured, matching reader.bricks()'s default.\n const MAIN_GRID = 1;\n const reader = WorldReader.from(new Uint8Array(readFileSync(file)));\n const bricks = nobricks\n ? []\n : [...reader.bricks(MAIN_GRID)].map(b => ({\n ...b,\n physical_index: 0,\n components: {} as Record<string, unknown>,\n }));\n\n // Attach components to their bricks. Components are stored per chunk with a\n // chunk-local brick index; reader.bricks() yields bricks in the same chunk\n // order as brickChunkIndex(), so a running offset maps the chunk-local\n // index onto the flat bricks array.\n if (!nobricks) {\n let brickOffset = 0;\n for (const chunk of reader.brickChunkIndex(MAIN_GRID)) {\n if (chunk.numComponents > 0) {\n const { components } = reader.componentChunk(MAIN_GRID, chunk.index);\n for (const c of components) {\n const brick = bricks[brickOffset + c.brickIndex];\n if (brick) brick.components[c.typeName] = c.data ?? {};\n }\n }\n brickOffset += chunk.numBricks;\n }\n }\n\n return {\n version: 10,\n map: omegga.currentMap ?? 'Unknown',\n author: { id: omegga.host?.id ?? '', name: omegga.host?.name ?? '' },\n host: { id: omegga.host?.id ?? '', name: omegga.host?.name ?? '' },\n description: '',\n brick_count: bricks.length,\n mods: [],\n brick_assets: reader.brickAssets(),\n colors: [],\n materials: reader.materials(),\n physical_materials: [],\n brick_owners: reader.brickOwners(),\n game_version: omegga.version,\n save_time: new Uint8Array(),\n bricks,\n components: {},\n } as ReadSaveObject;\n}\n\n/**\n * Write a save to a temporary `.brz` prefab in the prefab directory (EA3).\n * @returns the bare path ref for `br.Prefab.*` commands (no `Prefabs/` prefix\n * or `.brz` extension) and the absolute file path for cleanup.\n */\nfunction writeTempPrefab(\n omegga: {\n prefabPath: string;\n _tempSavePrefix: string;\n _tempCounter: { save: number };\n },\n saveData: WriteSaveObject,\n): { ref: string; file: string } {\n const ref =\n omegga._tempSavePrefix + Date.now() + '_' + omegga._tempCounter.save++;\n const file = join(omegga.prefabPath, ref + '.brz');\n if (!file.startsWith(omegga.prefabPath))\n throw 'prefab file not in Saved/Prefabs directory';\n mkdir(omegga.prefabPath);\n writeFileSync(file, new Uint8Array(writeBrzLegacy(saveData)));\n return { ref, file };\n}\n\n// TODO: safe broadcast parsing\n\nexport default class Omegga extends OmeggaWrapper implements OmeggaLike {\n /** The save counter prevents omegga from saving over the same file */\n _tempCounter = { save: 0, environment: 0 };\n /** The save prefix is prepended to all temporary saves */\n _tempSavePrefix = 'omegga_temp_';\n\n // pluginloader is not private so plugins can potentially add more formats\n pluginLoader: PluginLoader = undefined;\n webserver: Webserver;\n\n verbose: boolean;\n savePath: string;\n worldPath: string;\n prefabPath: string;\n presetPath: string;\n configPath: string;\n options: IOmeggaOptions;\n\n version: number;\n\n /** memoized version-resolved console commands ({@link Console}) */\n #console: { version: number; commands: ConsoleCommands };\n\n /**\n * version-resolved Brickadia console command names, nested by namespace.\n * e.g. `omegga.Console.Bricks.Clear` -> \"Bricks.Clear\" or \"br.Bricks.Clear\"\n * depending on the running game version.\n */\n get Console(): ConsoleCommands {\n if (this.#console?.version !== this.version)\n this.#console = {\n version: this.version,\n commands: resolveConsoleCommands(this.version),\n };\n return this.#console.commands;\n }\n\n host?: { id: string; name: string };\n players: OmeggaPlayer[];\n\n started = false;\n starting = false;\n stopping = false;\n crashDetected = false;\n currentMap: string;\n\n getServerStatus: () => Promise<IServerStatus>;\n listMinigames: () => Promise<IMinigameList>;\n getAllPlayerPositions: () => Promise<IPlayerPositions>;\n getMinigames: () => Promise<ILogMinigame[]>;\n getGamemode: () => Promise<IGamemode | null>;\n\n /**\n * Omegga instance\n */\n constructor(serverPath: string, cfg: IConfig, options: IOmeggaOptions = {}) {\n super(serverPath, cfg);\n this.verbose = Logger.VERBOSE;\n\n Logger.verbose('Running omegga', `v${VERSION}`.green);\n Logger.verbose('Versions', process.versions);\n Logger.verbose('Config', {\n ...cfg,\n credentials: cfg.credentials\n ? Object.fromEntries(\n Object.entries(cfg.credentials).map(([k, v]) => [k, v ? '***' : v]),\n )\n : cfg.credentials,\n server: {\n ...cfg.server,\n ...(cfg.server.password && { password: '***' }),\n ...(cfg.server.steambetaPassword && { steambetaPassword: '***' }),\n ...(cfg.server.launchArgs && {\n launchArgs: cfg.server.launchArgs\n .replace(/-Cookie=\".*?\"/g, '-Cookie=\"<hidden>\"')\n .replace(/-Cookie=\\S+/g, '-Cookie=<hidden>'),\n }),\n },\n });\n\n // inject commands\n Logger.verbose('Setting up command injector');\n commandInjector(this, this.logWrangler);\n\n // launch options (disabling webserver)\n this.options = options;\n const savedDir = cfg.server.savedDir ?? CONFIG_SAVED_DIR;\n\n // path to save files\n this.savePath = join(this.path, DATA_PATH, savedDir, 'Builds');\n this.worldPath = join(this.path, DATA_PATH, savedDir, 'Worlds');\n this.prefabPath = join(this.path, DATA_PATH, savedDir, 'Prefabs');\n\n this.presetPath = join(this.path, DATA_PATH, savedDir, 'Presets');\n\n // path to config files\n this.configPath = join(this.path, DATA_PATH, savedDir, 'Server');\n\n // create dir folders\n Logger.verbose('Creating directories');\n mkdir(this.savePath);\n mkdir(this.configPath);\n\n // ignore auth file copy\n if (!options.noauth) {\n Logger.verbose('Copying auth files');\n this.copyAuthFiles();\n }\n\n // create the webserver if it's enabled\n // the web interface provides access to server information while the server is running\n // and lets you view chat logs, disable plugins, etc\n if (!options.noweb) {\n Logger.verbose('Creating webserver');\n this.webserver = new Webserver(cfg.omegga, this);\n }\n\n if (!options.noplugin) {\n Logger.verbose('Creating plugin loader');\n this.pluginLoader = new PluginLoader(this.path, this);\n }\n\n /** @type {Array<Player>}list of online players */\n this.players = [];\n\n /** host player info `{id: uuid, name: player name}` */\n this.host = undefined;\n\n /** @type {String} current game version - may later be turned into CL#### versions */\n this.version = -1;\n\n /** @type {Boolean} whether server has started */\n this.started = false;\n /** @type {Boolean} whether server is starting up */\n this.starting = false;\n\n /** @type {String} current map */\n this.currentMap = '';\n\n // add all the matchers to the server\n Logger.verbose('Adding matchers');\n for (const matcher of MATCHERS) {\n const { pattern, callback } = matcher(this);\n this.addMatcher(pattern, callback);\n }\n\n process.on('uncaughtException', async err => {\n Logger.verbose('Uncaught exception', err);\n this.emit('error', err);\n\n // publish stop to database\n this.webserver?.database?.addChatLog('server', {}, 'Server error');\n\n try {\n await this.stop();\n } catch (e) {\n Logger.error(e);\n }\n process.exit();\n });\n\n // when brickadia starts, mark the server as started\n this.on('start', ({ map }) => {\n this.started = true;\n this.starting = false;\n this.currentMap = map;\n this.writeln(`${this.Console.Chat.MessageForUnknownCommands} 0`);\n\n this.restoreServer();\n });\n\n // detect engine crash from stderr or stdout\n const crashHandler = (line: string) => {\n if (\n !this.crashDetected &&\n (/Engine crash handling finished; re-raising signal \\d+ for the default handler\\. Good bye\\./.test(\n line,\n ) ||\n /LogCore: === Critical error: ===/.test(line))\n ) {\n Logger.error('Engine crash detected!');\n this.crashDetected = true;\n }\n };\n this.on('err', crashHandler);\n this.on('line', crashHandler);\n\n // when brickadia exits, stop omegga\n this.on('exit', () => {\n this.stop();\n });\n\n // when the process closes, emit the exit signal and stop\n this.on('closed', () => {\n // capture crash state before 'exit' handler triggers stop()\n const wasCrash = this.crashDetected;\n this.crashDetected = false;\n if (this.started) this.emit('exit');\n const doRestart = async () => {\n if (!wasCrash) return;\n try {\n const config = await this.webserver?.database?.getAutoRestartConfig();\n if (config?.crashRestartEnabled) {\n Logger.logp('Restarting server after crash...');\n this.webserver?.database?.addChatLog(\n 'server',\n {},\n 'Server crashed, restarting...',\n );\n await this.start();\n }\n } catch (err) {\n Logger.error('Error restarting after crash', err);\n }\n };\n if (!this.stopping) {\n this.stop().then(doRestart);\n } else {\n // stop() already in progress from 'exit' handler - wait for it to finish\n this.once('server:stopped', () => doRestart());\n }\n });\n\n // detect when the game reports a command does not exist\n this.on('unknownCommand', (name: string, cmd: string) => {\n // if it's not registered to a plugin, send the missing command message\n if (!this.pluginLoader || !this.pluginLoader.isCommand(cmd)) {\n this.whisper(name, MISSING_CMD);\n }\n });\n }\n\n /** attempt to save server state */\n async saveServer(config: AutoRestartConfig) {\n if (config.players && this.players.length > 0) {\n Logger.logp('Getting player positions...');\n const players = await this.getAllPlayerPositions();\n Logger.logp(`Saving ${players.length} player positions...`);\n const data = players\n .filter(p => !p.isDead && p.pos)\n .map(p => ({ position: p.pos, id: p.player.id }));\n if (players.length > 0)\n writeFileSync(\n join(this.path, DATA_PATH, 'omegga_temp_players.json'),\n JSON.stringify(data),\n );\n }\n\n if (config.saveWorld) {\n Logger.logp('Saving world...');\n await this.saveWorld();\n }\n }\n\n async restartServer() {\n if (this.starting || this.stopping) return;\n if (!this.started) return await this.start();\n\n const nextWorld = this.getNextWorld();\n if (nextWorld) {\n Logger.logp('Loading world', nextWorld.file.yellow);\n Logger.verbose('Next world configured from', nextWorld.source.yellow);\n this.loadWorld(nextWorld.file);\n } else {\n this.changeMap(this.currentMap);\n }\n\n const res = await Promise.race([\n // wait for the map to change\n new Promise(resolve =>\n this.once('mapchange', () => resolve('mapchange')),\n ),\n // Timeout after 10 seconds\n new Promise(resolve => setTimeout(() => resolve('timeout'), 10000)),\n ]);\n Logger.verbose('Restart result:', res);\n }\n\n /** attempt to restore the server's state */\n async restoreServer() {\n const tempPlayersFile = join(\n this.path,\n DATA_PATH,\n 'omegga_temp_players.json',\n );\n if (!existsSync(tempPlayersFile)) return;\n\n try {\n Logger.logp('Loading previous player positions...');\n\n // player positions are an array to address multi-clienting\n const players: { position: number[]; id: string }[] = JSON.parse(\n readFileSync(tempPlayersFile).toString(),\n );\n\n // restore player position on join\n const callback = (player: OmeggaPlayer) => {\n const index = players.findIndex(p => p.id === player.id);\n if (index > -1) {\n const { position } = players[index];\n this.writeln(\n `${this.Console.Chat.Command} /TP \"${player.name}\" ${position.join(' ')} 0`,\n );\n\n // remove the entry\n players[index] = players[players.length - 1];\n players.pop();\n }\n };\n this.on('join', callback);\n\n let timeout = setTimeout(() => {\n try {\n this.off('join', callback);\n if (existsSync(tempPlayersFile)) unlinkSync(tempPlayersFile);\n } catch (err) {\n Logger.error('Error removing omegga_temp_players.json', err);\n }\n }, 10000);\n this.once('changemap', () => {\n clearTimeout(timeout);\n this.off('join', callback);\n });\n } catch (err) {\n Logger.error('Error restoring previous server state', err);\n }\n }\n\n /**\n * start webserver, load plugins, start the brickadia server\n * this should not be called by a plugin\n */\n //\n async start(): Promise<any> {\n this.starting = true;\n\n // Resolve the game version straight from the server binary before plugins\n // load, so `omegga.version` is valid at plugin `init` time (e.g. for\n // readSaveData) instead of staying -1 until the game boots and writes its\n // log. The log parser (matchers/version) still runs and corrects this if\n // the binary read fails or the launcher path can't be resolved.\n if (this.version < 0) {\n const binVersion = readBinaryVersion(this.getGameBinaryPath());\n if (binVersion != null) {\n this.version = binVersion;\n Logger.verbose('Brickadia Version (from binary)', binVersion);\n }\n }\n\n if (this.webserver) await this.webserver.start();\n if (this.pluginLoader) {\n // scan for plugins\n Logger.verbose('Scanning for plugins');\n await this.pluginLoader.scan();\n\n // load the plugins\n Logger.verbose('Loading plugins');\n await this.pluginLoader.reload();\n }\n\n Logger.verbose('Starting Brickadia');\n super.start();\n this.emit('server:starting');\n }\n\n /**\n * unload plugins and stop the server\n * this should not be called by a plugin\n */\n async stop() {\n if (!this.started && !this.starting) {\n Logger.verbose(\"Stop called while server wasn't started or was starting\");\n return;\n }\n\n if (this.stopping) {\n Logger.verbose('Stop called while server was starting');\n return;\n }\n\n this.stopping = true;\n this.emit('server:stopping');\n if (this.pluginLoader) {\n Logger.verbose('Unloading plugins');\n await this.pluginLoader.unload();\n }\n Logger.verbose('Stopping server');\n super.stop();\n\n const res = await Promise.race([\n new Promise(resolve => this.once('exit', () => resolve('exit'))),\n // Timeout after 10 seconds\n new Promise(resolve => setTimeout(() => resolve('timeout'), 10000)),\n ]);\n\n Logger.verbose('Stop result:', res);\n if (this.stopping) this.emit('server:stopped');\n this.stopping = false;\n this.started = false;\n this.starting = false;\n this.players = [];\n }\n\n /**\n * Copies auth files from home config dir\n * this should never be called by a plugin\n */\n copyAuthFiles() {\n const authDir = this.config.server.authDir ?? CONFIG_AUTH_DIR;\n const savedDir = this.config.server.savedDir ?? CONFIG_SAVED_DIR;\n const authPath = join(this.path, DATA_PATH, savedDir, authDir);\n const homeAuthPath = join(\n CONFIG_HOME,\n (savedDir !== CONFIG_SAVED_DIR ? savedDir : '') + authDir,\n );\n\n copyFiles(homeAuthPath, authPath, BRICKADIA_AUTH_FILES);\n }\n\n // TODO: split messages that longer than 512 characters\n // TODO: delete characters that are known to crash the game\n broadcast(...messages: string[]) {\n messages\n .flatMap(m => m.toString().split('\\n'))\n .filter(m => m.length < 512)\n .forEach(m => this.writeln(`${this.Console.Chat.Broadcast} ${m}`));\n }\n\n whisper(target: string | OmeggaPlayer, ...messages: string[]) {\n // find the target player\n if (typeof target !== 'object') target = this.getPlayer(target);\n\n // player may have left before the message could be sent\n if (!target) return;\n\n // whisper the messages to that player\n messages\n .flatMap(m => m.toString().split('\\n'))\n .filter(m => m.length < 512)\n .forEach(m =>\n this.writeln(\n `${this.Console.Chat.Whisper} \"${(target as { name: string }).name}\" ${m}`,\n ),\n );\n }\n\n middlePrint(target: string | OmeggaPlayer, message: string) {\n // find the target player\n if (typeof target !== 'object') target = this.getPlayer(target);\n\n // player may have left before the message could be sent\n if (!target) return;\n\n // whisper the messages to that player\n if (message.length > 512) return;\n this.writeln(\n `${this.Console.Chat.StatusMessage} \"${(target as { name: string }).name}\" ${message}`,\n );\n }\n\n getPlayers(): {\n id: string;\n name: string;\n displayName: string;\n controller: string;\n state: string;\n }[] {\n return this.players.map(p => ({ ...p }));\n }\n\n getRoleSetup(): BRRoleSetup {\n // Read RoleSetup2, fallback to old RoleSetup if it doesn't exist\n return (readWatchedJSON(join(this.configPath, 'RoleSetup2.json')) ??\n readWatchedJSON(join(this.configPath, 'RoleSetup.json'))) as BRRoleSetup;\n }\n\n getRoleAssignments(): BRRoleAssignments {\n return readWatchedJSON(\n join(this.configPath, 'RoleAssignments.json'),\n ) as BRRoleAssignments;\n }\n\n getBanList(): BRBanList {\n return readWatchedJSON(join(this.configPath, 'BanList.json')) as BRBanList;\n }\n\n getNameCache(): BRPlayerNameCache {\n return readWatchedJSON(\n join(this.configPath, 'PlayerNameCache.json'),\n ) as BRPlayerNameCache;\n }\n\n getPlayer(target: string): OmeggaPlayer {\n return this.players.find(\n p =>\n p.name === target ||\n p.id === target ||\n p.controller === target ||\n p.state === target,\n );\n }\n\n findPlayerByName(name: string): OmeggaPlayer {\n name = name.toLowerCase();\n const exploded = pattern.explode(name);\n return (\n this.players.find(p => p.name === name || p.displayName === name) || // find by exact match\n this.players.find(\n p => p.name.indexOf(name) > -1 || p.displayName.indexOf(name) > -1,\n ) || // find by rough match\n this.players.find(\n p => p.name.match(exploded) || p.displayName.match(exploded),\n ) // find by exploded regex match (ck finds cake, tbp finds TheBlackParrot)\n );\n }\n\n getHostId(): string {\n return this.host?.id ?? '';\n }\n\n saveMinigame(index: number, name: string) {\n this.writeln(\n `${this.Console.Server.Minigames.SavePreset} ${index} \"${name}\"`,\n );\n }\n\n deleteMinigame(index: number) {\n this.writeln(`${this.Console.Server.Minigames.Delete} ${index}`);\n }\n\n resetMinigame(index: number) {\n this.writeln(`${this.Console.Server.Minigames.Reset} ${index}`);\n }\n\n nextRoundMinigame(index: number) {\n this.writeln(`${this.Console.Server.Minigames.NextRound} ${index}`);\n }\n\n loadMinigame(presetName: string, owner = '') {\n this.writeln(\n `${this.Console.Server.Minigames.LoadPreset} \"${presetName}\" ${owner ? `\"${owner}\"` : ''}`,\n );\n }\n\n getMinigamePresets(): string[] {\n const presetPath = join(this.presetPath, 'Minigame');\n return existsSync(presetPath)\n ? glob\n .sync(presetPath + '/**/*.bp')\n .map(f => basename(f).replace(/\\.bp$/, ''))\n : [];\n }\n\n resetEnvironment() {\n this.writeln(`${this.Console.Server.Environment.Reset}`);\n }\n\n async saveEnvironment(presetName: string): Promise<void> {\n await this.addWatcher(/Environment preset saved.$/, {\n // request the pawn for this player's controller (should only be one)\n exec: () =>\n this.writeln(\n `${this.Console.Server.Environment.SavePreset} \"${presetName}\"`,\n ),\n timeoutDelay: 100,\n });\n }\n\n async getEnvironmentData(): Promise<EnvironmentPreset> {\n const saveName =\n this._tempSavePrefix + Date.now() + '_' + this._tempCounter.environment++;\n\n await this.saveEnvironment(saveName);\n const data = this.readEnvironmentData(saveName);\n const file = join(this.presetPath, 'Environment', saveName + '.bp');\n if (existsSync(file)) unlinkSync(file);\n\n return data;\n }\n\n readEnvironmentData(saveName: string): EnvironmentPreset {\n if (typeof saveName !== 'string')\n throw 'expected name argument for readEnvironmentData';\n\n const file = join(this.presetPath, 'Environment', saveName + '.bp');\n try {\n if (existsSync(file)) return JSON.parse(readFileSync(file).toString());\n } catch (err) {\n Logger.verbose('Error parsing save data in readEnvironmentData', err);\n }\n return null;\n }\n\n loadEnvironment(presetName: string) {\n this.writeln(`${this.Console.Server.Environment.LoadPreset} ${presetName}`);\n }\n\n loadEnvironmentData(\n preset: EnvironmentPreset | EnvironmentPreset['data']['groups'],\n ) {\n if ('data' in preset) preset = preset.data.groups;\n\n const saveFile =\n this._tempSavePrefix + Date.now() + '_' + this._tempCounter.environment++;\n\n const path = join(this.presetPath, 'Environment', saveFile + '.bp');\n\n writeFileSync(\n path,\n JSON.stringify({\n formatVersion: '1',\n presetVersion: '1',\n type: 'Environment',\n data: {\n groups: {\n ...preset,\n },\n },\n }),\n );\n\n this.loadEnvironment(saveFile);\n\n // this is lazy, but environments should load much faster than builds\n // do, so it's not really worth keeping track of logs for this\n setTimeout(() => unlinkSync(path), 5000);\n }\n\n getEnvironmentPresets(): string[] {\n const presetPath = join(this.presetPath, 'Environment');\n return existsSync(presetPath)\n ? glob\n .sync(presetPath + '/**/*.bp')\n .map(f => basename(f).replace(/\\.bp$/, ''))\n : [];\n }\n\n clearBricks(target: string | { id: string }, quiet = false) {\n // target is a player object, just use that id\n if (typeof target === 'object' && target.id) target = target.id;\n // if the target isn't a uuid already, find the player by name or controller and use that uuid\n else if (typeof target === 'string' && !uuid.match(target)) {\n // only set the target if the player exists\n const player = this.getPlayer(target);\n target = player && player.id;\n }\n\n if (!target) return;\n\n this.writeln(`${this.Console.Bricks.Clear} ${target} ${quiet ? 1 : ''}`);\n }\n\n clearRegion(\n region: {\n center: [number, number, number];\n extent: [number, number, number];\n },\n options?: {\n target?: string | OmeggaPlayer;\n /** clear bricks in the region (default true) */\n bricks?: boolean;\n /** also clear entities in the region (default false, EA3 only) */\n entities?: boolean;\n },\n ) {\n // resolve the optional owner filter (player object, uuid, or name) to a uuid\n let target = '';\n const rawTarget = options?.target;\n if (rawTarget) {\n if (typeof rawTarget === 'object') target = rawTarget.id;\n else if (uuid.match(rawTarget)) target = rawTarget;\n else target = this.getPlayer(rawTarget)?.id ?? '';\n }\n\n const center = region.center.join(' ');\n const extent = region.extent.join(' ');\n\n if (brsRemoved(this.version)) {\n // br.World.ClearRegion <Center> <Extent> [ClearBricks] [ClearEntities] [FilterUserId]\n const bricks = (options?.bricks ?? true) ? 1 : 0;\n const entities = (options?.entities ?? false) ? 1 : 0;\n this.writeln(\n `${this.Console.World.ClearRegion} ${center} ${extent} ${bricks} ${entities}${\n target ? ' ' + target : ''\n }`,\n );\n return;\n }\n\n // legacy .brs region clear (bricks only)\n this.writeln(\n `${this.Console.Bricks.ClearRegion} ${center} ${extent}${\n target ? ' ' + target : ''\n }`,\n );\n }\n\n clearAllBricks(\n options:\n | boolean\n | { quiet?: boolean; bricks?: boolean; entities?: boolean } = {},\n ) {\n // backwards compat: a bare boolean is the legacy `quiet` argument\n const {\n quiet = false,\n bricks = true,\n entities = false,\n } = typeof options === 'boolean' ? { quiet: options } : options;\n\n if (brsRemoved(this.version)) {\n // br.World.ClearAll [ClearBricks] [ClearEntities] [Silent]\n this.writeln(\n `${this.Console.World.ClearAll} ${bricks ? 1 : 0} ${\n entities ? 1 : 0\n } ${quiet ? 1 : 0}`,\n );\n return;\n }\n // legacy Bricks.ClearAll only ever cleared bricks\n this.writeln(`${this.Console.Bricks.ClearAll} ${quiet ? 1 : ''}`);\n }\n\n saveBricks(\n saveName: string,\n region?: {\n center: [number, number, number];\n extent: [number, number, number];\n },\n ) {\n if (\n warnRemoved(\n this.version,\n 'saveBricks',\n PREFAB_VERSION,\n 'EA3',\n 'savePrefab',\n )\n )\n return;\n if (!saveName) return;\n\n // add quotes around the filename if it doesn't have them (backwards compat w/ plugins)\n if (!(saveName.startsWith('\"') && saveName.endsWith('\"')))\n saveName = `\"${saveName}\"`;\n\n if (region?.center && region?.extent)\n this.writeln(\n `${this.Console.Bricks.SaveRegion} ${saveName} ${region.center.join(\n ' ',\n )} ${region.extent.join(' ')}`,\n );\n else this.writeln(`${this.Console.Bricks.Save} ${saveName}`);\n }\n\n async saveBricksAsync(\n saveName: string,\n region?: {\n center: [number, number, number];\n extent: [number, number, number];\n },\n ): Promise<void> {\n if (\n warnRemoved(\n this.version,\n 'saveBricksAsync',\n PREFAB_VERSION,\n 'EA3',\n 'savePrefabAsync',\n )\n )\n return;\n if (!saveName) return;\n\n let saveNameClean = saveName;\n // add quotes around the filename if it doesn't have them (backwards compat w/ plugins)\n if (!(saveName.startsWith('\"') && saveName.endsWith('\"')))\n saveNameClean = `\"${saveName}\"`;\n\n const command =\n region?.center && region?.extent\n ? `${this.Console.Bricks.SaveRegion} ${saveNameClean} ${region.center.join(\n ' ',\n )} ${region.extent.join(' ')}`\n : `${this.Console.Bricks.Save} ${saveNameClean}`;\n\n // wait for the server to save the file\n await this.watchLogChunk(command, /^(LogBrickSerializer|LogTemp): (.+)$/, {\n first: match => match[0].endsWith(saveName + '.brs...'),\n last: match =>\n Boolean(\n match[2].match(\n /Saved .+ bricks and .+ components from .+ owners|Error: No bricks in grid!|Error: No bricks selected to save!/,\n ),\n ),\n afterMatchDelay: 0,\n timeoutDelay: 30000,\n });\n }\n\n loadBricks(\n saveName: string,\n {\n offX = 0,\n offY = 0,\n offZ = 0,\n quiet = false,\n correctPalette = false,\n correctCustom = false,\n } = {},\n ) {\n if (\n warnRemoved(\n this.version,\n 'loadBricks',\n PREFAB_VERSION,\n 'EA3',\n 'loadPrefab',\n )\n )\n return;\n // add quotes around the filename if it doesn't have them (backwards compat w/ plugins)\n if (!(saveName.startsWith('\"') && saveName.endsWith('\"')))\n saveName = `\"${saveName}\"`;\n\n this.writeln(\n `${this.Console.Bricks.Load} ${saveName} ${offX} ${offY} ${offZ} ${\n quiet ? 1 : 0\n } ${correctPalette ? 1 : 0} ${correctCustom ? 1 : 0}`,\n );\n }\n\n loadBricksOnPlayer(\n saveName: string,\n player: string | OmeggaPlayer,\n {\n offX = 0,\n offY = 0,\n offZ = 0,\n correctPalette = false,\n correctCustom = false,\n } = {},\n ) {\n if (\n warnRemoved(\n this.version,\n 'loadBricksOnPlayer',\n EA2_VERSION,\n 'EA2',\n 'loadPrefabOnPlayer',\n )\n )\n return;\n player = typeof player === 'string' ? this.getPlayer(player) : player;\n if (!player) return;\n\n // add quotes around the filename if it doesn't have them (backwards compat w/ plugins)\n if (!(saveName.startsWith('\"') && saveName.endsWith('\"')))\n saveName = `\"${saveName}\"`;\n\n this.writeln(\n `${this.Console.Bricks.LoadTemplate} ${saveName} ${offX} ${offY} ${offZ} ${\n correctPalette ? 1 : 0\n } ${correctCustom ? 1 : 0} \"${player.name}\"`,\n );\n }\n\n getSaves(): string[] {\n return existsSync(this.savePath)\n ? glob.sync(this.savePath + '/**/*.brs')\n : [];\n }\n\n getWorlds(): string[] {\n return existsSync(this.worldPath)\n ? glob.sync(this.worldPath + '/**/*.brdb')\n : [];\n }\n\n getPrefabs(): string[] {\n return existsSync(this.prefabPath)\n ? glob.sync(this.prefabPath + '/**/*.brz')\n : [];\n }\n\n getSavePath(saveName: string) {\n return resolveInDir(this.savePath, saveName, '.brs');\n }\n\n getPrefabPath(prefabName: string) {\n return resolveInDir(this.prefabPath, prefabName, '.brz');\n }\n\n getWorldPath(worldName: string) {\n return resolveInDir(this.worldPath, worldName, '.brdb');\n }\n\n async getWorldRevisions(worldName: string) {\n worldName = worldName.replace(/\\.brdb$/i, '');\n\n const path = this.getWorldPath(worldName);\n if (!worldName || !path) {\n throw new Error(`World \"${worldName}\" does not exist`);\n }\n\n // Revisions are read directly from the .brdb bundle (SQLite), so this no\n // longer requires the server to be running or a console round-trip. The\n // brdb revision indices/notes match the game's World.ListRevisions output.\n return readBrdbRevisions(path) ?? [];\n }\n\n async loadWorld(worldName: string): Promise<boolean> {\n worldName = worldName.replace(/\\.brdb$/i, '');\n if (!worldName || !this.getWorldPath(worldName)) return false;\n this.writeln(`${this.Console.World.Load} \"${worldName}\"`);\n const res = await Promise.race([\n // wait for the map to change\n new Promise(resolve =>\n this.once('mapchange', () => resolve('mapchange')),\n ),\n // Timeout after 10 seconds\n new Promise(resolve => setTimeout(() => resolve('timeout'), 10000)),\n ]);\n Logger.verbose('LoadWorld', worldName, 'result:', res);\n return res === 'mapchange';\n }\n\n async loadWorldRevision(\n worldName: string,\n revision: number,\n ): Promise<boolean> {\n worldName = worldName.replace(/\\.brdb$/i, '');\n if (!worldName || !this.getWorldPath(worldName)) return false;\n if (typeof revision !== 'number' || revision < 1) {\n throw new Error(`Invalid revision number: ${revision}`);\n }\n this.writeln(\n `${this.Console.World.LoadRevision} \"${worldName}\" ${revision}`,\n );\n const res = await Promise.race([\n // wait for the map to change\n new Promise(resolve =>\n this.once('mapchange', () => resolve('mapchange')),\n ),\n // Timeout after 10 seconds\n new Promise(resolve => setTimeout(() => resolve('timeout'), 10000)),\n ]);\n Logger.verbose('LoadWorld', worldName, 'result:', res);\n return res === 'mapchange';\n }\n\n async saveWorldAs(worldName: string) {\n if (!worldName) return false;\n if (this.stopping || this.starting || !this.started) return false;\n\n if (this.getWorldPath(worldName)) {\n return false;\n }\n worldName = worldName.replace(/\\.brdb$/i, '');\n\n try {\n const match = await this.addWatcher<{ res: boolean }>(\n (_line, match) => {\n if (match?.groups?.generator !== 'LogBRWorldManager') return;\n\n const ok = match.groups.data.match(/^World files saved after /);\n const err =\n !match.groups.data.startsWith(\n 'Error: Failed to capture minigame settings',\n ) &&\n match.groups.data.match(\n /^Error: (World already exists|Failed to create new world)?/,\n );\n return ok ? { res: true } : err ? { res: false } : undefined;\n },\n {\n exec: () => {\n this.writeln(`${this.Console.World.SaveAs} \"${worldName}\"`);\n },\n timeoutDelay: 2000,\n },\n );\n return match?.[0]?.['res'] ?? false;\n } catch (err) {\n return false;\n }\n }\n\n async saveWorld(): Promise<boolean> {\n // Don't allow saving while the server is starting or stopping\n if (this.stopping || this.starting || !this.started) return false;\n\n try {\n const match = await this.addWatcher<{ res: boolean }>(\n (_line, match) => {\n if (match?.groups?.generator !== 'LogBRWorldManager') return;\n\n const ok = match.groups.data.match(/^World files saved after /);\n const err =\n !match.groups.data.startsWith(\n 'Error: Failed to capture minigame settings',\n ) &&\n match.groups.data.match(/^Error: (World has not been saved\\.)?/);\n return ok ? { res: true } : err ? { res: false } : undefined;\n },\n {\n exec: () => {\n this.writeln(`${this.Console.World.Save} 0`);\n },\n timeoutDelay: 2000,\n },\n );\n return match?.[0]?.['res'] ?? false;\n } catch (err) {\n return false;\n }\n }\n\n async createEmptyWorld(\n worldName: string,\n map: 'Plate' | 'Space' | 'Studio' | 'Peaks' = 'Plate',\n ): Promise<boolean> {\n if (!worldName) return;\n worldName = worldName.replace(/\\.brdb$/i, '');\n\n try {\n const match = await this.addWatcher<{ res: boolean }>(\n (_line, match) => {\n if (match?.groups?.generator !== 'LogBRWorldManager') return;\n\n const ok = match.groups.data.match(/^World files saved after /);\n const err = match.groups.data.match(\n /^Error: (Invalid preset|World already exists|Failed to create new world)?/,\n );\n return ok ? { res: true } : err ? { res: false } : undefined;\n },\n {\n exec: () => {\n this.writeln(\n `${this.Console.World.CreateEmpty} \"${worldName}\" ${map}`,\n );\n },\n timeoutDelay: 2000,\n },\n );\n return match?.[0]?.['res'] ?? false;\n } catch (err) {\n return false;\n }\n }\n\n writeSaveData(saveName: string, saveData: WriteSaveObject) {\n if (typeof saveName !== 'string')\n throw 'expected name argument for writeSaveData';\n\n const file = join(this.savePath, saveName + '.brs');\n if (!file.startsWith(this.savePath))\n throw 'save file not in Saved/Builds directory';\n writeFileSync(file, new Uint8Array(brs.write(saveData)));\n }\n\n readSaveData(saveName: string, nobricks = false): ReadSaveObject {\n if (typeof saveName !== 'string')\n throw 'expected name argument for readSaveData';\n\n // EA3: the legacy .brs format is gone; saved builds are `.brz` prefabs.\n // Read the named prefab and reconstruct a legacy save object, mirroring\n // getSaveData's EA3 path.\n if (brsRemoved(this.version)) {\n const file = this.getPrefabPath(saveName);\n if (!file || !file.startsWith(this.prefabPath))\n throw 'prefab file not in Saved/Prefabs directory';\n return readPrefabData(this, file, { nobricks });\n }\n\n const file = this.getSavePath(saveName);\n if (!file || !file.startsWith(this.savePath))\n throw 'save file not in Saved/Builds directory';\n if (file)\n return brs.read(readFileSync(file), {\n preview: false,\n bricks: !nobricks,\n });\n }\n\n async loadSaveData(\n saveData: WriteSaveObject,\n {\n offX = 0,\n offY = 0,\n offZ = 0,\n quiet = false,\n correctPalette = false,\n correctCustom = false,\n } = {},\n ) {\n // EA3: the legacy Bricks.Load command was removed. Convert the save to a\n // .brz prefab and load it into the world via br.Prefab.Load. The palette\n // correction flags have no prefab equivalent and are ignored.\n if (brsRemoved(this.version)) {\n const { ref, file } = writeTempPrefab(this, saveData);\n this.loadPrefab(ref, { offX, offY, offZ });\n // the server reads the prefab synchronously and auto-closes the bundle a\n // couple seconds later; clean up the temp file lazily (cf. loadEnvironment)\n setTimeout(() => {\n if (existsSync(file)) unlinkSync(file);\n }, 5000);\n return;\n }\n\n const saveFile =\n this._tempSavePrefix + Date.now() + '_' + this._tempCounter.save++;\n // write savedata to file\n this.writeSaveData(saveFile, saveData);\n\n // wait for the server to finish reading the save\n await this.watchLogChunk(\n `${this.Console.Bricks.Load} \"${saveFile}\" ${offX} ${offY} ${offZ} ${quiet ? 1 : 0} ${\n correctPalette ? 1 : 0\n } ${correctCustom ? 1 : 0}`,\n /^LogBrickSerializer: (.+)$/,\n {\n first: match => match[0].endsWith(saveFile + '.brs...'),\n last: match => Boolean(match[1].match(/Read .+ bricks/)),\n afterMatchDelay: 0,\n timeoutDelay: 30000,\n },\n );\n\n // delete the save file after we're done\n const savePath = this.getSavePath(saveFile);\n if (savePath) {\n unlinkSync(savePath);\n }\n }\n\n async loadSaveDataOnPlayer(\n saveData: WriteSaveObject,\n player: string | OmeggaPlayer,\n {\n offX = 0,\n offY = 0,\n offZ = 0,\n correctPalette = false,\n correctCustom = false,\n } = {},\n ) {\n player = typeof player === 'string' ? this.getPlayer(player) : player;\n if (!player) return;\n\n // EA3: give the save to the player as a prefab (their inventory) via\n // br.Prefab.GiveToPlayer. Offsets have no equivalent and are ignored,\n // matching loadPrefabOnPlayer.\n if (brsRemoved(this.version)) {\n const { ref, file } = writeTempPrefab(this, saveData);\n this.givePrefabToPlayer(ref, player);\n setTimeout(() => {\n if (existsSync(file)) unlinkSync(file);\n }, 5000);\n return;\n }\n\n // The Bricks.LoadTemplate command was removed at EA2, before the prefab\n // commands existed; there is no working path on that intermediate version.\n if (\n warnRemoved(\n this.version,\n 'loadSaveDataOnPlayer',\n EA2_VERSION,\n 'EA2',\n 'loadPrefabOnPlayer',\n )\n )\n return;\n\n const saveFile =\n this._tempSavePrefix + Date.now() + '_' + this._tempCounter.save++;\n // write savedata to file\n this.writeSaveData(saveFile, saveData);\n\n // wait for the server to finish reading the save\n await this.watchLogChunk(\n `${this.Console.Bricks.LoadTemplate} \"${saveFile}\" ${offX} ${offY} ${offZ} ${\n correctPalette ? 1 : 0\n } ${correctCustom ? 1 : 0} \"${player.name}\"`,\n /^LogBrickSerializer: (.+)$/,\n {\n first: match => match[0].endsWith(saveFile + '.brs...'),\n last: match => Boolean(match[1].match(/Read .+ bricks/)),\n afterMatchDelay: 0,\n timeoutDelay: 30000,\n },\n );\n\n // delete the save file after we're done\n const savePath = this.getSavePath(saveFile);\n if (savePath) {\n unlinkSync(savePath);\n }\n }\n\n async getSaveData(region?: {\n center: [number, number, number];\n extent: [number, number, number];\n }) {\n // EA3: the legacy Bricks.Save command was removed. Save the world (or the\n // requested region) as a .brz prefab, then read it back into a legacy save\n // object. Brick geometry, ownership, assets, materials, colors, and\n // components are reconstructed; wires are not (the save-level `wires`\n // array is left empty). Component names/data are EA3-native (e.g.\n // `Component_Internal_Seat`), not the legacy `BCD_*` names.\n if (brsRemoved(this.version)) {\n const ref =\n this._tempSavePrefix + Date.now() + '_' + this._tempCounter.save++;\n const file = await this.savePrefabAsync(ref, { region });\n if (!file) return undefined;\n\n try {\n return readPrefabData(this, file);\n } finally {\n if (existsSync(file)) unlinkSync(file);\n }\n }\n\n const saveFile =\n this._tempSavePrefix + Date.now() + '_' + this._tempCounter.save++;\n\n await this.saveBricksAsync(saveFile, region);\n\n // read the save file\n const savePath = this.getSavePath(saveFile);\n if (savePath) {\n // read and parse the save file\n const saveData = brs.read(readFileSync(savePath));\n\n // delete the save file after we're done reading it\n unlinkSync(savePath);\n\n // return the parsed save\n return saveData;\n }\n\n return undefined;\n }\n\n /**\n * Load a prefab into the world (EA3). `path` is a bundle\n * path ref such as `Prefabs/Uploads/<hash>.brz`.\n * br.Prefab.Load <Path> [Offset X Y Z] [At Original Position] [Orientation]\n * [Root Entity Persistent Index] [Mirror Axes] [Override User Id]\n */\n loadPrefab(\n path: string,\n {\n offX = 0,\n offY = 0,\n offZ = 0,\n atOriginalPosition = false,\n orientation = 0,\n rootEntityPersistentIndex = -1,\n mirrorAxes = 0,\n overrideUserId = '',\n }: {\n offX?: number;\n offY?: number;\n offZ?: number;\n atOriginalPosition?: boolean;\n orientation?: number;\n rootEntityPersistentIndex?: number;\n /** bitmask: X=1 Y=2 Z=4 (e.g. 3 mirrors X and Y) */\n mirrorAxes?: number;\n overrideUserId?: string;\n } = {},\n ) {\n if (!path) return;\n // The root entity persistent index is looked up as a literal brick-grid\n // entity, so passing the -1 sentinel errors (\"No brick grid entity with\n // persistent index 4294967295\"). Omit it (and the positional args after\n // it) to load into the world grid; only include it when a real index is\n // given.\n const rootPart =\n rootEntityPersistentIndex >= 0\n ? ` ${rootEntityPersistentIndex} ${mirrorAxes}${\n overrideUserId ? ` \"${overrideUserId}\"` : ''\n }`\n : '';\n this.writeln(\n `${this.Console.Prefab.Load} \"${path}\" ${offX} ${offY} ${offZ} ${\n atOriginalPosition ? 1 : 0\n } ${orientation}${rootPart}`,\n );\n }\n\n /**\n * Load a prefab onto a player (EA3). Replaces the\n * removed {@link loadBricksOnPlayer}; backed by `br.Prefab.GiveToPlayer`.\n * @param path prefab bundle path ref\n * @param player player name/id or player object\n * @param options give options (preserve ownership)\n */\n loadPrefabOnPlayer(\n path: string,\n player: string | OmeggaPlayer,\n { preserveOwnership = false }: { preserveOwnership?: boolean } = {},\n ) {\n this.givePrefabToPlayer(path, player, { preserveOwnership });\n }\n\n /**\n * Save the world (or a region of it) as a prefab (EA3).\n * `path` is the destination bundle path ref (e.g. `Prefabs/MyPrefab.brz`).\n * br.Prefab.SaveRegion <Path> <Center X Y Z> <Extent X Y Z> [Include Entities]\n * [Root Entity Persistent Index] [Filter User Id]\n * @param path destination prefab bundle path ref\n * @param options save options; omit `region` to capture the whole world\n */\n savePrefab(\n path: string,\n {\n region,\n entities = true,\n rootEntityPersistentIndex = -1,\n userId = '',\n }: {\n region?: {\n center: [number, number, number];\n extent: [number, number, number];\n };\n entities?: boolean;\n rootEntityPersistentIndex?: number;\n userId?: string;\n } = {},\n ) {\n if (!path) return;\n // the command always takes a region; with none given, capture the whole\n // world from the origin with a maximal extent\n const center = (region?.center ?? [0, 0, 0]).join(' ');\n const extent = (\n region?.extent ?? [\n WHOLE_WORLD_EXTENT,\n WHOLE_WORLD_EXTENT,\n WHOLE_WORLD_EXTENT,\n ]\n ).join(' ');\n // As in loadPrefab, the root entity persistent index is looked up as a\n // literal brick-grid entity, so passing the -1 sentinel fails with\n // \"No brick grid entity with persistent index 4294967295\" and nothing is\n // written. Omit it (and the user id after it) to save from the world grid.\n const rootPart =\n rootEntityPersistentIndex >= 0\n ? ` ${rootEntityPersistentIndex}${userId ? ` \"${userId}\"` : ''}`\n : '';\n this.writeln(\n `${this.Console.Prefab.SaveRegion} \"${path}\" ${center} ${extent} ${\n entities ? 1 : 0\n }${rootPart}`,\n );\n }\n\n /**\n * Save a prefab and resolve once the prefab file has been written to disk.\n * @param path destination prefab bundle path ref\n * @param options same options as {@link savePrefab}\n * @returns the absolute path to the written prefab, or null on timeout\n */\n async savePrefabAsync(\n path: string,\n options?: {\n region?: {\n center: [number, number, number];\n extent: [number, number, number];\n };\n entities?: boolean;\n rootEntityPersistentIndex?: number;\n userId?: string;\n },\n ): Promise<string | null> {\n if (!path) return null;\n this.savePrefab(path, options);\n\n // TODO: confirm the write via the prefab-saved log line once its exact\n // format is nailed down; for now poll for the written file on disk.\n const name = path.replace(/^Prefabs[\\\\/]/i, '').replace(/\\.brz$/i, '');\n const file = join(this.prefabPath, name + '.brz');\n const deadline = Date.now() + 30000;\n while (Date.now() < deadline) {\n if (existsSync(file)) return file;\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n return null;\n }\n\n /**\n * Give a prefab to a player's inventory (EA3).\n * br.Prefab.GiveToPlayer <Path> <Player Name or User Id> [Preserve Ownership]\n */\n givePrefabToPlayer(\n path: string,\n player: string | OmeggaPlayer,\n { preserveOwnership = false }: { preserveOwnership?: boolean } = {},\n ) {\n if (!path) return;\n // the command accepts a player name or user id; prefer the resolved id\n const target = typeof player === 'object' ? player.id : player;\n if (!target) return;\n this.writeln(\n `${this.Console.Prefab.GiveToPlayer} \"${path}\" \"${target}\" ${\n preserveOwnership ? 1 : 0\n }`,\n );\n }\n\n // TODO: switch this to use worlds...\n async changeMap(map: string) {\n if (!map) return;\n\n // ServerTravel requires /Game/Maps/Plate/Plate instead of Plate\n const brName = mapUtils.n2brn(map);\n\n // wait for the server to change maps\n const match = await this.addWatcher(\n /^.*(LogLoad: Took .+ seconds to LoadMap\\((?<map>.+)\\))|(ERROR: The map .+)$/,\n {\n timeoutDelay: 30000,\n exec: () => this.writeln(`ServerTravel ${brName}`),\n },\n );\n const success = !!(\n match &&\n match[0] &&\n match[0].groups &&\n match[0].groups.map\n );\n return success;\n }\n\n async getPlugin(name: string): Promise<PluginInterop> {\n const plugin = this.pluginLoader.plugins.find(p => p.getName() === name);\n\n if (plugin) {\n return {\n name,\n documentation: plugin.getDocumentation(),\n loaded: plugin.isLoaded(),\n emitPlugin: (event: string, ...args: any[]) => {\n return plugin.emitPlugin(event, 'unsafe', args);\n },\n };\n } else {\n return null;\n }\n }\n}\n"],"names":["version","PREFAB_VERSION","Logger","file","resolve","sep","existsSync","WorldReader","readFileSync","join","mkdir","writeFileSync","writeBrzLegacy","OmeggaWrapper","VERSION","commandInjector","CONFIG_SAVED_DIR","DATA_PATH","Webserver","PluginLoader","MATCHERS","pattern","resolveConsoleCommands","index","unlinkSync","readBinaryVersion","CONFIG_AUTH_DIR","CONFIG_HOME","copyFiles","BRICKADIA_AUTH_FILES","readWatchedJSON","basename","path","uuid","EA2_VERSION","readBrdbRevisions","match","mapUtils","plugin"],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sources":["../../src/omegga/server.ts"],"sourcesContent":["import Logger from '@/logger';\nimport { OmeggaLike, OmeggaPlayer, PluginInterop } from '@/plugin';\nimport {\n BRICKADIA_AUTH_FILES,\n CONFIG_AUTH_DIR,\n CONFIG_HOME,\n CONFIG_SAVED_DIR,\n DATA_PATH,\n} from '@/softconfig';\nimport { VERSION } from '@/version';\nimport { EnvironmentPreset } from '@brickadia/presets';\nimport {\n BRBanList,\n BRPlayerNameCache,\n BRRoleAssignments,\n BRRoleSetup,\n} from '@brickadia/types';\nimport { IConfig } from '@config/types';\nimport { map as mapUtils, pattern, uuid } from '@util';\nimport { readBrdbRevisions } from '@util/brdb';\nimport { copyFiles, mkdir, readWatchedJSON } from '@util/file';\nimport Webserver from '@webserver/backend';\nimport brs, {\n WorldReader,\n writeBrzLegacy,\n type ReadSaveObject,\n type WriteSaveObject,\n} from 'brs-js';\nimport 'colors';\nimport glob from 'glob';\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\nimport { basename, join, resolve, sep } from 'path';\nimport { AutoRestartConfig } from '..';\nimport commandInjector from './commandInjector';\nimport {\n ConsoleCommands,\n EA2_VERSION,\n PREFAB_VERSION,\n resolveConsoleCommands,\n} from './commands';\nimport MATCHERS from './matchers';\nimport { readBinaryVersion } from './matchers/version';\nimport Player from './player';\nimport { PluginLoader } from './plugin';\nimport {\n IGamemode,\n ILogMinigame,\n IMinigameList,\n IOmeggaOptions,\n IPlayerPositions,\n IServerStatus,\n} from './types';\nimport OmeggaWrapper from './wrapper';\n\nconst MISSING_CMD =\n '\"Command not found. Type <color=\\\\\"ffff00\\\\\">/help</> for a list of commands or <color=\\\\\"ffff00\\\\\">/plugins</> for plugin information.\"';\n\n// Prefab.SaveRegion requires a region; when saving the whole world we pass a\n// maximal extent centered on the origin to capture everything.\nconst WHOLE_WORLD_EXTENT = 1_000_000_000;\n\n// These helpers are module-level (not class methods) on purpose: safe plugins\n// call these methods through a ProxyOmegga whose prototype steals Omegga's\n// implementations (see injectOmeggaPrototypes). A `#private` method would fail\n// the brand check when `this` is a ProxyOmegga (\"Receiver must be an instance\n// of class Omegga\"), so anything a stolen method depends on must not be\n// `#private`. Module functions keep working regardless of the receiver.\n\n/**\n * Whether the running game version has removed the legacy .brs bricks console\n * commands (Bricks.Save/Load/ClearAll/ClearRegion, World.LoadAdditive) in\n * favor of the prefab (`br.Prefab.*`) and world (`br.World.Clear*`) commands.\n * Removed at Brickadia CL{@link PREFAB_VERSION}.\n */\nfunction brsRemoved(version: number): boolean {\n return version > 0 && version >= PREFAB_VERSION;\n}\n\n/**\n * Warn that a method backed by a removed console command is a no-op on the\n * running game version, and return whether the caller should bail.\n * @param version the running game version\n * @param method the omegga method being called (for the message)\n * @param since CL version the underlying command was removed at\n * @param release human release name for that version (e.g. `EA2`, `EA3`)\n * @param replacement suggested replacement method/API\n */\nfunction warnRemoved(\n version: number,\n method: string,\n since: number,\n release: string,\n replacement: string,\n): boolean {\n if (!(version > 0 && version >= since)) return false;\n Logger.warnp(\n `omegga.${method}() uses a console command removed in Brickadia ` +\n `${release}. This call has no effect - use ${replacement} instead.`,\n );\n return true;\n}\n\n/**\n * Resolve `name` to an existing file inside `dir`, appending `ext` when it is\n * missing. `name` may be a bare name, a relative path, or an absolute path --\n * `resolve` (unlike `join`) lets callers pass an absolute path from one of\n * these getters straight back into an api that takes a name.\n * @returns the absolute path, or undefined if it does not exist or escapes `dir`\n */\nexport function resolveInDir(\n dir: string,\n name: string,\n ext: string,\n): string | undefined {\n if (typeof name !== 'string' || !name) return undefined;\n const file = resolve(\n dir,\n name.toLowerCase().endsWith(ext) ? name : name + ext,\n );\n // keep the file inside dir (guards against `..` traversal)\n if (!file.startsWith(dir.endsWith(sep) ? dir : dir + sep)) return undefined;\n return existsSync(file) ? file : undefined;\n}\n\n/**\n * Read a `.brz` prefab file (EA3) into a legacy save object. Brick geometry,\n * ownership, assets, materials, and components are reconstructed; wires are\n * not (the save-level `wires` array is left empty). Component names/data are\n * EA3-native (e.g. `Component_Internal_Seat`), not the legacy `BCD_*` names.\n *\n * This is a plain function rather than a method because `readSaveData` and\n * `getSaveData` are handed to safe plugins via STEAL_PROTOTYPES and run with\n * `this` bound to the plugin's proxy omegga, which has no private methods on\n * it -- calling `this.readPrefabData(...)` there throws \"not a function\".\n */\nfunction readPrefabData(\n omegga: {\n version: number;\n currentMap?: string;\n host?: { id: string; name: string };\n },\n file: string,\n { nobricks = false } = {},\n): ReadSaveObject {\n // gridId 1 is the world's main brick grid (MAIN_GRID); entity sub-grids\n // (>=2) are not captured, matching reader.bricks()'s default.\n const MAIN_GRID = 1;\n const reader = WorldReader.from(new Uint8Array(readFileSync(file)));\n const bricks = nobricks\n ? []\n : [...reader.bricks(MAIN_GRID)].map(b => ({\n ...b,\n physical_index: 0,\n components: {} as Record<string, unknown>,\n }));\n\n // Attach components to their bricks. Components are stored per chunk with a\n // chunk-local brick index; reader.bricks() yields bricks in the same chunk\n // order as brickChunkIndex(), so a running offset maps the chunk-local\n // index onto the flat bricks array.\n if (!nobricks) {\n let brickOffset = 0;\n for (const chunk of reader.brickChunkIndex(MAIN_GRID)) {\n if (chunk.numComponents > 0) {\n const { components } = reader.componentChunk(MAIN_GRID, chunk.index);\n for (const c of components) {\n const brick = bricks[brickOffset + c.brickIndex];\n if (brick) brick.components[c.typeName] = c.data ?? {};\n }\n }\n brickOffset += chunk.numBricks;\n }\n }\n\n return {\n version: 10,\n map: omegga.currentMap ?? 'Unknown',\n author: { id: omegga.host?.id ?? '', name: omegga.host?.name ?? '' },\n host: { id: omegga.host?.id ?? '', name: omegga.host?.name ?? '' },\n description: '',\n brick_count: bricks.length,\n mods: [],\n brick_assets: reader.brickAssets(),\n colors: [],\n materials: reader.materials(),\n physical_materials: [],\n brick_owners: reader.brickOwners(),\n game_version: omegga.version,\n save_time: new Uint8Array(),\n bricks,\n components: {},\n } as ReadSaveObject;\n}\n\n/**\n * Write a save to a temporary `.brz` prefab in the prefab directory (EA3).\n * @returns the bare path ref for `br.Prefab.*` commands (no `Prefabs/` prefix\n * or `.brz` extension) and the absolute file path for cleanup.\n */\nfunction writeTempPrefab(\n omegga: {\n prefabPath: string;\n _tempSavePrefix: string;\n _tempCounter: { save: number };\n },\n saveData: WriteSaveObject,\n): { ref: string; file: string } {\n const ref =\n omegga._tempSavePrefix + Date.now() + '_' + omegga._tempCounter.save++;\n const file = join(omegga.prefabPath, ref + '.brz');\n if (!file.startsWith(omegga.prefabPath))\n throw 'prefab file not in Saved/Prefabs directory';\n mkdir(omegga.prefabPath);\n writeFileSync(file, new Uint8Array(writeBrzLegacy(saveData)));\n return { ref, file };\n}\n\n// TODO: safe broadcast parsing\n\nexport default class Omegga extends OmeggaWrapper implements OmeggaLike {\n /** The save counter prevents omegga from saving over the same file */\n _tempCounter = { save: 0, environment: 0 };\n /** The save prefix is prepended to all temporary saves */\n _tempSavePrefix = 'omegga_temp_';\n\n // pluginloader is not private so plugins can potentially add more formats\n pluginLoader: PluginLoader = undefined;\n webserver: Webserver;\n\n verbose: boolean;\n savePath: string;\n worldPath: string;\n prefabPath: string;\n presetPath: string;\n configPath: string;\n options: IOmeggaOptions;\n\n version: number;\n\n /** memoized version-resolved console commands ({@link Console}) */\n #console: { version: number; commands: ConsoleCommands };\n\n /**\n * version-resolved Brickadia console command names, nested by namespace.\n * e.g. `omegga.Console.Bricks.Clear` -> \"Bricks.Clear\" or \"br.Bricks.Clear\"\n * depending on the running game version.\n */\n get Console(): ConsoleCommands {\n if (this.#console?.version !== this.version)\n this.#console = {\n version: this.version,\n commands: resolveConsoleCommands(this.version),\n };\n return this.#console.commands;\n }\n\n host?: { id: string; name: string };\n players: OmeggaPlayer[];\n\n started = false;\n starting = false;\n stopping = false;\n crashDetected = false;\n currentMap: string;\n\n getServerStatus: () => Promise<IServerStatus>;\n listMinigames: () => Promise<IMinigameList>;\n getAllPlayerPositions: () => Promise<IPlayerPositions>;\n getMinigames: () => Promise<ILogMinigame[]>;\n getGamemode: () => Promise<IGamemode | null>;\n\n /**\n * Omegga instance\n */\n constructor(serverPath: string, cfg: IConfig, options: IOmeggaOptions = {}) {\n super(serverPath, cfg);\n this.verbose = Logger.VERBOSE;\n\n Logger.verbose('Running omegga', `v${VERSION}`.green);\n Logger.verbose('Versions', process.versions);\n Logger.verbose('Config', {\n ...cfg,\n credentials: cfg.credentials\n ? Object.fromEntries(\n Object.entries(cfg.credentials).map(([k, v]) => [k, v ? '***' : v]),\n )\n : cfg.credentials,\n server: {\n ...cfg.server,\n ...(cfg.server.password && { password: '***' }),\n ...(cfg.server.steambetaPassword && { steambetaPassword: '***' }),\n ...(cfg.server.launchArgs && {\n launchArgs: cfg.server.launchArgs\n .replace(/-Cookie=\".*?\"/g, '-Cookie=\"<hidden>\"')\n .replace(/-Cookie=\\S+/g, '-Cookie=<hidden>'),\n }),\n },\n });\n\n // inject commands\n Logger.verbose('Setting up command injector');\n commandInjector(this, this.logWrangler);\n\n // launch options (disabling webserver)\n this.options = options;\n const savedDir = cfg.server.savedDir ?? CONFIG_SAVED_DIR;\n\n // path to save files\n this.savePath = join(this.path, DATA_PATH, savedDir, 'Builds');\n this.worldPath = join(this.path, DATA_PATH, savedDir, 'Worlds');\n this.prefabPath = join(this.path, DATA_PATH, savedDir, 'Prefabs');\n\n this.presetPath = join(this.path, DATA_PATH, savedDir, 'Presets');\n\n // path to config files\n this.configPath = join(this.path, DATA_PATH, savedDir, 'Server');\n\n // create dir folders\n Logger.verbose('Creating directories');\n mkdir(this.savePath);\n mkdir(this.configPath);\n\n // ignore auth file copy\n if (!options.noauth) {\n Logger.verbose('Copying auth files');\n this.copyAuthFiles();\n }\n\n // create the webserver if it's enabled\n // the web interface provides access to server information while the server is running\n // and lets you view chat logs, disable plugins, etc\n if (!options.noweb) {\n Logger.verbose('Creating webserver');\n this.webserver = new Webserver(cfg.omegga, this);\n }\n\n if (!options.noplugin) {\n Logger.verbose('Creating plugin loader');\n this.pluginLoader = new PluginLoader(this.path, this);\n }\n\n /** @type {Array<Player>}list of online players */\n this.players = [];\n\n /** host player info `{id: uuid, name: player name}` */\n this.host = undefined;\n\n /** @type {String} current game version - may later be turned into CL#### versions */\n this.version = -1;\n\n /** @type {Boolean} whether server has started */\n this.started = false;\n /** @type {Boolean} whether server is starting up */\n this.starting = false;\n\n /** @type {String} current map */\n this.currentMap = '';\n\n // add all the matchers to the server\n Logger.verbose('Adding matchers');\n for (const matcher of MATCHERS) {\n const { pattern, callback } = matcher(this);\n this.addMatcher(pattern, callback);\n }\n\n process.on('uncaughtException', async err => {\n Logger.verbose('Uncaught exception', err);\n this.emit('error', err);\n\n // publish stop to database\n this.webserver?.database?.addChatLog('server', {}, 'Server error');\n\n try {\n await this.stop();\n } catch (e) {\n Logger.error(e);\n }\n process.exit();\n });\n\n // when brickadia starts, mark the server as started\n this.on('start', ({ map }) => {\n this.started = true;\n this.starting = false;\n this.currentMap = map;\n this.writeln(`${this.Console.Chat.MessageForUnknownCommands} 0`);\n\n this.restoreServer();\n });\n\n // detect engine crash from stderr or stdout\n const crashHandler = (line: string) => {\n if (\n !this.crashDetected &&\n (/Engine crash handling finished; re-raising signal \\d+ for the default handler\\. Good bye\\./.test(\n line,\n ) ||\n /LogCore: === Critical error: ===/.test(line))\n ) {\n Logger.error('Engine crash detected!');\n this.crashDetected = true;\n }\n };\n this.on('err', crashHandler);\n this.on('line', crashHandler);\n\n // when brickadia exits, stop omegga\n this.on('exit', () => {\n this.stop();\n });\n\n // when the process closes, emit the exit signal and stop\n this.on('closed', () => {\n // capture crash state before 'exit' handler triggers stop()\n const wasCrash = this.crashDetected;\n this.crashDetected = false;\n if (this.started) this.emit('exit');\n const doRestart = async () => {\n if (!wasCrash) return;\n try {\n const config = await this.webserver?.database?.getAutoRestartConfig();\n if (config?.crashRestartEnabled) {\n Logger.logp('Restarting server after crash...');\n this.webserver?.database?.addChatLog(\n 'server',\n {},\n 'Server crashed, restarting...',\n );\n await this.start();\n }\n } catch (err) {\n Logger.error('Error restarting after crash', err);\n }\n };\n if (!this.stopping) {\n this.stop().then(doRestart);\n } else {\n // stop() already in progress from 'exit' handler - wait for it to finish\n this.once('server:stopped', () => doRestart());\n }\n });\n\n // detect when the game reports a command does not exist\n this.on('unknownCommand', (name: string, cmd: string) => {\n // if it's not registered to a plugin, send the missing command message\n if (!this.pluginLoader || !this.pluginLoader.isCommand(cmd)) {\n this.whisper(name, MISSING_CMD);\n }\n });\n }\n\n /** attempt to save server state */\n async saveServer(config: AutoRestartConfig) {\n if (config.players && this.players.length > 0) {\n Logger.logp('Getting player positions...');\n const players = await this.getAllPlayerPositions();\n Logger.logp(`Saving ${players.length} player positions...`);\n const data = players\n .filter(p => !p.isDead && p.pos)\n .map(p => ({ position: p.pos, id: p.player.id }));\n if (players.length > 0)\n writeFileSync(\n join(this.path, DATA_PATH, 'omegga_temp_players.json'),\n JSON.stringify(data),\n );\n }\n\n if (config.saveWorld) {\n Logger.logp('Saving world...');\n await this.saveWorld();\n }\n }\n\n async restartServer() {\n if (this.starting || this.stopping) return;\n if (!this.started) return await this.start();\n\n const nextWorld = this.getNextWorld();\n if (nextWorld) {\n Logger.logp('Loading world', nextWorld.file.yellow);\n Logger.verbose('Next world configured from', nextWorld.source.yellow);\n this.loadWorld(nextWorld.file);\n } else {\n this.changeMap(this.currentMap);\n }\n\n const res = await Promise.race([\n // wait for the map to change\n new Promise(resolve =>\n this.once('mapchange', () => resolve('mapchange')),\n ),\n // Timeout after 10 seconds\n new Promise(resolve => setTimeout(() => resolve('timeout'), 10000)),\n ]);\n Logger.verbose('Restart result:', res);\n }\n\n /** attempt to restore the server's state */\n async restoreServer() {\n const tempPlayersFile = join(\n this.path,\n DATA_PATH,\n 'omegga_temp_players.json',\n );\n if (!existsSync(tempPlayersFile)) return;\n\n try {\n Logger.logp('Loading previous player positions...');\n\n // player positions are an array to address multi-clienting\n const players: { position: number[]; id: string }[] = JSON.parse(\n readFileSync(tempPlayersFile).toString(),\n );\n\n // restore player position on join\n const callback = (player: OmeggaPlayer) => {\n const index = players.findIndex(p => p.id === player.id);\n if (index > -1) {\n const { position } = players[index];\n this.writeln(\n `${this.Console.Chat.Command} /TP \"${player.name}\" ${position.join(' ')} 0`,\n );\n\n // remove the entry\n players[index] = players[players.length - 1];\n players.pop();\n }\n };\n this.on('join', callback);\n\n let timeout = setTimeout(() => {\n try {\n this.off('join', callback);\n if (existsSync(tempPlayersFile)) unlinkSync(tempPlayersFile);\n } catch (err) {\n Logger.error('Error removing omegga_temp_players.json', err);\n }\n }, 10000);\n this.once('changemap', () => {\n clearTimeout(timeout);\n this.off('join', callback);\n });\n } catch (err) {\n Logger.error('Error restoring previous server state', err);\n }\n }\n\n /**\n * start webserver, load plugins, start the brickadia server\n * this should not be called by a plugin\n */\n //\n async start(): Promise<any> {\n this.starting = true;\n\n // Resolve the game version straight from the server binary before plugins\n // load, so `omegga.version` is valid at plugin `init` time (e.g. for\n // readSaveData) instead of staying -1 until the game boots and writes its\n // log.\n //\n // This re-resolves on every start, not just the first: a steam update can\n // replace the binary between restarts (the process is reused by the crash\n // handler and restartServer), so a version cached from a previous boot goes\n // stale. When the binary can't be read (e.g. launcher-managed installs) we\n // reset to -1 so the log parser (matchers/version) re-detects this boot.\n const binVersion = readBinaryVersion(this.getGameBinaryPath());\n this.version = binVersion ?? -1;\n if (binVersion != null) {\n Logger.verbose('Brickadia Version (from binary)', binVersion);\n // plugins that aren't reloaded on restart only learn the new version\n // through this event (reloaded ones get it via bootstrap)\n this.emit('version', binVersion);\n }\n\n if (this.webserver) await this.webserver.start();\n if (this.pluginLoader) {\n // scan for plugins\n Logger.verbose('Scanning for plugins');\n await this.pluginLoader.scan();\n\n // load the plugins\n Logger.verbose('Loading plugins');\n await this.pluginLoader.reload();\n }\n\n Logger.verbose('Starting Brickadia');\n super.start();\n this.emit('server:starting');\n }\n\n /**\n * unload plugins and stop the server\n * this should not be called by a plugin\n */\n async stop() {\n if (!this.started && !this.starting) {\n Logger.verbose(\"Stop called while server wasn't started or was starting\");\n return;\n }\n\n if (this.stopping) {\n Logger.verbose('Stop called while server was starting');\n return;\n }\n\n this.stopping = true;\n this.emit('server:stopping');\n if (this.pluginLoader) {\n Logger.verbose('Unloading plugins');\n await this.pluginLoader.unload();\n }\n Logger.verbose('Stopping server');\n super.stop();\n\n const res = await Promise.race([\n new Promise(resolve => this.once('exit', () => resolve('exit'))),\n // Timeout after 10 seconds\n new Promise(resolve => setTimeout(() => resolve('timeout'), 10000)),\n ]);\n\n Logger.verbose('Stop result:', res);\n if (this.stopping) this.emit('server:stopped');\n this.stopping = false;\n this.started = false;\n this.starting = false;\n this.players = [];\n }\n\n /**\n * Copies auth files from home config dir\n * this should never be called by a plugin\n */\n copyAuthFiles() {\n const authDir = this.config.server.authDir ?? CONFIG_AUTH_DIR;\n const savedDir = this.config.server.savedDir ?? CONFIG_SAVED_DIR;\n const authPath = join(this.path, DATA_PATH, savedDir, authDir);\n const homeAuthPath = join(\n CONFIG_HOME,\n (savedDir !== CONFIG_SAVED_DIR ? savedDir : '') + authDir,\n );\n\n copyFiles(homeAuthPath, authPath, BRICKADIA_AUTH_FILES);\n }\n\n // TODO: split messages that longer than 512 characters\n // TODO: delete characters that are known to crash the game\n broadcast(...messages: string[]) {\n messages\n .flatMap(m => m.toString().split('\\n'))\n .filter(m => m.length < 512)\n .forEach(m => this.writeln(`${this.Console.Chat.Broadcast} ${m}`));\n }\n\n whisper(target: string | OmeggaPlayer, ...messages: string[]) {\n // find the target player\n if (typeof target !== 'object') target = this.getPlayer(target);\n\n // player may have left before the message could be sent\n if (!target) return;\n\n // whisper the messages to that player\n messages\n .flatMap(m => m.toString().split('\\n'))\n .filter(m => m.length < 512)\n .forEach(m =>\n this.writeln(\n `${this.Console.Chat.Whisper} \"${(target as { name: string }).name}\" ${m}`,\n ),\n );\n }\n\n middlePrint(target: string | OmeggaPlayer, message: string) {\n // find the target player\n if (typeof target !== 'object') target = this.getPlayer(target);\n\n // player may have left before the message could be sent\n if (!target) return;\n\n // whisper the messages to that player\n if (message.length > 512) return;\n this.writeln(\n `${this.Console.Chat.StatusMessage} \"${(target as { name: string }).name}\" ${message}`,\n );\n }\n\n getPlayers(): {\n id: string;\n name: string;\n displayName: string;\n controller: string;\n state: string;\n }[] {\n return this.players.map(p => ({ ...p }));\n }\n\n getRoleSetup(): BRRoleSetup {\n // Read RoleSetup2, fallback to old RoleSetup if it doesn't exist\n return (readWatchedJSON(join(this.configPath, 'RoleSetup2.json')) ??\n readWatchedJSON(join(this.configPath, 'RoleSetup.json'))) as BRRoleSetup;\n }\n\n getRoleAssignments(): BRRoleAssignments {\n return readWatchedJSON(\n join(this.configPath, 'RoleAssignments.json'),\n ) as BRRoleAssignments;\n }\n\n getBanList(): BRBanList {\n return readWatchedJSON(join(this.configPath, 'BanList.json')) as BRBanList;\n }\n\n getNameCache(): BRPlayerNameCache {\n return readWatchedJSON(\n join(this.configPath, 'PlayerNameCache.json'),\n ) as BRPlayerNameCache;\n }\n\n getPlayer(target: string): OmeggaPlayer {\n return this.players.find(\n p =>\n p.name === target ||\n p.id === target ||\n p.controller === target ||\n p.state === target,\n );\n }\n\n findPlayerByName(name: string): OmeggaPlayer {\n name = name.toLowerCase();\n const exploded = pattern.explode(name);\n return (\n this.players.find(p => p.name === name || p.displayName === name) || // find by exact match\n this.players.find(\n p => p.name.indexOf(name) > -1 || p.displayName.indexOf(name) > -1,\n ) || // find by rough match\n this.players.find(\n p => p.name.match(exploded) || p.displayName.match(exploded),\n ) // find by exploded regex match (ck finds cake, tbp finds TheBlackParrot)\n );\n }\n\n getHostId(): string {\n return this.host?.id ?? '';\n }\n\n saveMinigame(index: number, name: string) {\n this.writeln(\n `${this.Console.Server.Minigames.SavePreset} ${index} \"${name}\"`,\n );\n }\n\n deleteMinigame(index: number) {\n this.writeln(`${this.Console.Server.Minigames.Delete} ${index}`);\n }\n\n resetMinigame(index: number) {\n this.writeln(`${this.Console.Server.Minigames.Reset} ${index}`);\n }\n\n nextRoundMinigame(index: number) {\n this.writeln(`${this.Console.Server.Minigames.NextRound} ${index}`);\n }\n\n loadMinigame(presetName: string, owner = '') {\n this.writeln(\n `${this.Console.Server.Minigames.LoadPreset} \"${presetName}\" ${owner ? `\"${owner}\"` : ''}`,\n );\n }\n\n getMinigamePresets(): string[] {\n const presetPath = join(this.presetPath, 'Minigame');\n return existsSync(presetPath)\n ? glob\n .sync(presetPath + '/**/*.bp')\n .map(f => basename(f).replace(/\\.bp$/, ''))\n : [];\n }\n\n resetEnvironment() {\n this.writeln(`${this.Console.Server.Environment.Reset}`);\n }\n\n async saveEnvironment(presetName: string): Promise<void> {\n await this.addWatcher(/Environment preset saved.$/, {\n // request the pawn for this player's controller (should only be one)\n exec: () =>\n this.writeln(\n `${this.Console.Server.Environment.SavePreset} \"${presetName}\"`,\n ),\n timeoutDelay: 100,\n });\n }\n\n async getEnvironmentData(): Promise<EnvironmentPreset> {\n const saveName =\n this._tempSavePrefix + Date.now() + '_' + this._tempCounter.environment++;\n\n await this.saveEnvironment(saveName);\n const data = this.readEnvironmentData(saveName);\n const file = join(this.presetPath, 'Environment', saveName + '.bp');\n if (existsSync(file)) unlinkSync(file);\n\n return data;\n }\n\n readEnvironmentData(saveName: string): EnvironmentPreset {\n if (typeof saveName !== 'string')\n throw 'expected name argument for readEnvironmentData';\n\n const file = join(this.presetPath, 'Environment', saveName + '.bp');\n try {\n if (existsSync(file)) return JSON.parse(readFileSync(file).toString());\n } catch (err) {\n Logger.verbose('Error parsing save data in readEnvironmentData', err);\n }\n return null;\n }\n\n loadEnvironment(presetName: string) {\n this.writeln(`${this.Console.Server.Environment.LoadPreset} ${presetName}`);\n }\n\n loadEnvironmentData(\n preset: EnvironmentPreset | EnvironmentPreset['data']['groups'],\n ) {\n if ('data' in preset) preset = preset.data.groups;\n\n const saveFile =\n this._tempSavePrefix + Date.now() + '_' + this._tempCounter.environment++;\n\n const path = join(this.presetPath, 'Environment', saveFile + '.bp');\n\n writeFileSync(\n path,\n JSON.stringify({\n formatVersion: '1',\n presetVersion: '1',\n type: 'Environment',\n data: {\n groups: {\n ...preset,\n },\n },\n }),\n );\n\n this.loadEnvironment(saveFile);\n\n // this is lazy, but environments should load much faster than builds\n // do, so it's not really worth keeping track of logs for this\n setTimeout(() => unlinkSync(path), 5000);\n }\n\n getEnvironmentPresets(): string[] {\n const presetPath = join(this.presetPath, 'Environment');\n return existsSync(presetPath)\n ? glob\n .sync(presetPath + '/**/*.bp')\n .map(f => basename(f).replace(/\\.bp$/, ''))\n : [];\n }\n\n clearBricks(target: string | { id: string }, quiet = false) {\n // target is a player object, just use that id\n if (typeof target === 'object' && target.id) target = target.id;\n // if the target isn't a uuid already, find the player by name or controller and use that uuid\n else if (typeof target === 'string' && !uuid.match(target)) {\n // only set the target if the player exists\n const player = this.getPlayer(target);\n target = player && player.id;\n }\n\n if (!target) return;\n\n this.writeln(`${this.Console.Bricks.Clear} ${target} ${quiet ? 1 : ''}`);\n }\n\n clearRegion(\n region: {\n center: [number, number, number];\n extent: [number, number, number];\n },\n options?: {\n target?: string | OmeggaPlayer;\n /** clear bricks in the region (default true) */\n bricks?: boolean;\n /** also clear entities in the region (default false, EA3 only) */\n entities?: boolean;\n },\n ) {\n // resolve the optional owner filter (player object, uuid, or name) to a uuid\n let target = '';\n const rawTarget = options?.target;\n if (rawTarget) {\n if (typeof rawTarget === 'object') target = rawTarget.id;\n else if (uuid.match(rawTarget)) target = rawTarget;\n else target = this.getPlayer(rawTarget)?.id ?? '';\n }\n\n const center = region.center.join(' ');\n const extent = region.extent.join(' ');\n\n if (brsRemoved(this.version)) {\n // br.World.ClearRegion <Center> <Extent> [ClearBricks] [ClearEntities] [FilterUserId]\n const bricks = (options?.bricks ?? true) ? 1 : 0;\n const entities = (options?.entities ?? false) ? 1 : 0;\n this.writeln(\n `${this.Console.World.ClearRegion} ${center} ${extent} ${bricks} ${entities}${\n target ? ' ' + target : ''\n }`,\n );\n return;\n }\n\n // legacy .brs region clear (bricks only)\n this.writeln(\n `${this.Console.Bricks.ClearRegion} ${center} ${extent}${\n target ? ' ' + target : ''\n }`,\n );\n }\n\n clearAllBricks(\n options:\n | boolean\n | { quiet?: boolean; bricks?: boolean; entities?: boolean } = {},\n ) {\n // backwards compat: a bare boolean is the legacy `quiet` argument\n const {\n quiet = false,\n bricks = true,\n entities = false,\n } = typeof options === 'boolean' ? { quiet: options } : options;\n\n if (brsRemoved(this.version)) {\n // br.World.ClearAll [ClearBricks] [ClearEntities] [Silent]\n this.writeln(\n `${this.Console.World.ClearAll} ${bricks ? 1 : 0} ${\n entities ? 1 : 0\n } ${quiet ? 1 : 0}`,\n );\n return;\n }\n // legacy Bricks.ClearAll only ever cleared bricks\n this.writeln(`${this.Console.Bricks.ClearAll} ${quiet ? 1 : ''}`);\n }\n\n saveBricks(\n saveName: string,\n region?: {\n center: [number, number, number];\n extent: [number, number, number];\n },\n ) {\n if (\n warnRemoved(\n this.version,\n 'saveBricks',\n PREFAB_VERSION,\n 'EA3',\n 'savePrefab',\n )\n )\n return;\n if (!saveName) return;\n\n // add quotes around the filename if it doesn't have them (backwards compat w/ plugins)\n if (!(saveName.startsWith('\"') && saveName.endsWith('\"')))\n saveName = `\"${saveName}\"`;\n\n if (region?.center && region?.extent)\n this.writeln(\n `${this.Console.Bricks.SaveRegion} ${saveName} ${region.center.join(\n ' ',\n )} ${region.extent.join(' ')}`,\n );\n else this.writeln(`${this.Console.Bricks.Save} ${saveName}`);\n }\n\n async saveBricksAsync(\n saveName: string,\n region?: {\n center: [number, number, number];\n extent: [number, number, number];\n },\n ): Promise<void> {\n if (\n warnRemoved(\n this.version,\n 'saveBricksAsync',\n PREFAB_VERSION,\n 'EA3',\n 'savePrefabAsync',\n )\n )\n return;\n if (!saveName) return;\n\n let saveNameClean = saveName;\n // add quotes around the filename if it doesn't have them (backwards compat w/ plugins)\n if (!(saveName.startsWith('\"') && saveName.endsWith('\"')))\n saveNameClean = `\"${saveName}\"`;\n\n const command =\n region?.center && region?.extent\n ? `${this.Console.Bricks.SaveRegion} ${saveNameClean} ${region.center.join(\n ' ',\n )} ${region.extent.join(' ')}`\n : `${this.Console.Bricks.Save} ${saveNameClean}`;\n\n // wait for the server to save the file\n await this.watchLogChunk(command, /^(LogBrickSerializer|LogTemp): (.+)$/, {\n first: match => match[0].endsWith(saveName + '.brs...'),\n last: match =>\n Boolean(\n match[2].match(\n /Saved .+ bricks and .+ components from .+ owners|Error: No bricks in grid!|Error: No bricks selected to save!/,\n ),\n ),\n afterMatchDelay: 0,\n timeoutDelay: 30000,\n });\n }\n\n loadBricks(\n saveName: string,\n {\n offX = 0,\n offY = 0,\n offZ = 0,\n quiet = false,\n correctPalette = false,\n correctCustom = false,\n } = {},\n ) {\n if (\n warnRemoved(\n this.version,\n 'loadBricks',\n PREFAB_VERSION,\n 'EA3',\n 'loadPrefab',\n )\n )\n return;\n // add quotes around the filename if it doesn't have them (backwards compat w/ plugins)\n if (!(saveName.startsWith('\"') && saveName.endsWith('\"')))\n saveName = `\"${saveName}\"`;\n\n this.writeln(\n `${this.Console.Bricks.Load} ${saveName} ${offX} ${offY} ${offZ} ${\n quiet ? 1 : 0\n } ${correctPalette ? 1 : 0} ${correctCustom ? 1 : 0}`,\n );\n }\n\n loadBricksOnPlayer(\n saveName: string,\n player: string | OmeggaPlayer,\n {\n offX = 0,\n offY = 0,\n offZ = 0,\n correctPalette = false,\n correctCustom = false,\n } = {},\n ) {\n if (\n warnRemoved(\n this.version,\n 'loadBricksOnPlayer',\n EA2_VERSION,\n 'EA2',\n 'loadPrefabOnPlayer',\n )\n )\n return;\n player = typeof player === 'string' ? this.getPlayer(player) : player;\n if (!player) return;\n\n // add quotes around the filename if it doesn't have them (backwards compat w/ plugins)\n if (!(saveName.startsWith('\"') && saveName.endsWith('\"')))\n saveName = `\"${saveName}\"`;\n\n this.writeln(\n `${this.Console.Bricks.LoadTemplate} ${saveName} ${offX} ${offY} ${offZ} ${\n correctPalette ? 1 : 0\n } ${correctCustom ? 1 : 0} \"${player.name}\"`,\n );\n }\n\n getSaves(): string[] {\n return existsSync(this.savePath)\n ? glob.sync(this.savePath + '/**/*.brs')\n : [];\n }\n\n getWorlds(): string[] {\n return existsSync(this.worldPath)\n ? glob.sync(this.worldPath + '/**/*.brdb')\n : [];\n }\n\n getPrefabs(): string[] {\n return existsSync(this.prefabPath)\n ? glob.sync(this.prefabPath + '/**/*.brz')\n : [];\n }\n\n getSavePath(saveName: string) {\n return resolveInDir(this.savePath, saveName, '.brs');\n }\n\n getPrefabPath(prefabName: string) {\n return resolveInDir(this.prefabPath, prefabName, '.brz');\n }\n\n getWorldPath(worldName: string) {\n return resolveInDir(this.worldPath, worldName, '.brdb');\n }\n\n async getWorldRevisions(worldName: string) {\n worldName = worldName.replace(/\\.brdb$/i, '');\n\n const path = this.getWorldPath(worldName);\n if (!worldName || !path) {\n throw new Error(`World \"${worldName}\" does not exist`);\n }\n\n // Revisions are read directly from the .brdb bundle (SQLite), so this no\n // longer requires the server to be running or a console round-trip. The\n // brdb revision indices/notes match the game's World.ListRevisions output.\n return readBrdbRevisions(path) ?? [];\n }\n\n async loadWorld(worldName: string): Promise<boolean> {\n worldName = worldName.replace(/\\.brdb$/i, '');\n if (!worldName || !this.getWorldPath(worldName)) return false;\n this.writeln(`${this.Console.World.Load} \"${worldName}\"`);\n const res = await Promise.race([\n // wait for the map to change\n new Promise(resolve =>\n this.once('mapchange', () => resolve('mapchange')),\n ),\n // Timeout after 10 seconds\n new Promise(resolve => setTimeout(() => resolve('timeout'), 10000)),\n ]);\n Logger.verbose('LoadWorld', worldName, 'result:', res);\n return res === 'mapchange';\n }\n\n async loadWorldRevision(\n worldName: string,\n revision: number,\n ): Promise<boolean> {\n worldName = worldName.replace(/\\.brdb$/i, '');\n if (!worldName || !this.getWorldPath(worldName)) return false;\n if (typeof revision !== 'number' || revision < 1) {\n throw new Error(`Invalid revision number: ${revision}`);\n }\n this.writeln(\n `${this.Console.World.LoadRevision} \"${worldName}\" ${revision}`,\n );\n const res = await Promise.race([\n // wait for the map to change\n new Promise(resolve =>\n this.once('mapchange', () => resolve('mapchange')),\n ),\n // Timeout after 10 seconds\n new Promise(resolve => setTimeout(() => resolve('timeout'), 10000)),\n ]);\n Logger.verbose('LoadWorld', worldName, 'result:', res);\n return res === 'mapchange';\n }\n\n async saveWorldAs(worldName: string) {\n if (!worldName) return false;\n if (this.stopping || this.starting || !this.started) return false;\n\n if (this.getWorldPath(worldName)) {\n return false;\n }\n worldName = worldName.replace(/\\.brdb$/i, '');\n\n try {\n const match = await this.addWatcher<{ res: boolean }>(\n (_line, match) => {\n if (match?.groups?.generator !== 'LogBRWorldManager') return;\n\n const ok = match.groups.data.match(/^World files saved after /);\n const err =\n !match.groups.data.startsWith(\n 'Error: Failed to capture minigame settings',\n ) &&\n match.groups.data.match(\n /^Error: (World already exists|Failed to create new world)?/,\n );\n return ok ? { res: true } : err ? { res: false } : undefined;\n },\n {\n exec: () => {\n this.writeln(`${this.Console.World.SaveAs} \"${worldName}\"`);\n },\n timeoutDelay: 2000,\n },\n );\n return match?.[0]?.['res'] ?? false;\n } catch (err) {\n return false;\n }\n }\n\n async saveWorld(): Promise<boolean> {\n // Don't allow saving while the server is starting or stopping\n if (this.stopping || this.starting || !this.started) return false;\n\n try {\n const match = await this.addWatcher<{ res: boolean }>(\n (_line, match) => {\n if (match?.groups?.generator !== 'LogBRWorldManager') return;\n\n const ok = match.groups.data.match(/^World files saved after /);\n const err =\n !match.groups.data.startsWith(\n 'Error: Failed to capture minigame settings',\n ) &&\n match.groups.data.match(/^Error: (World has not been saved\\.)?/);\n return ok ? { res: true } : err ? { res: false } : undefined;\n },\n {\n exec: () => {\n this.writeln(`${this.Console.World.Save} 0`);\n },\n timeoutDelay: 2000,\n },\n );\n return match?.[0]?.['res'] ?? false;\n } catch (err) {\n return false;\n }\n }\n\n async createEmptyWorld(\n worldName: string,\n map: 'Plate' | 'Space' | 'Studio' | 'Peaks' = 'Plate',\n ): Promise<boolean> {\n if (!worldName) return;\n worldName = worldName.replace(/\\.brdb$/i, '');\n\n try {\n const match = await this.addWatcher<{ res: boolean }>(\n (_line, match) => {\n if (match?.groups?.generator !== 'LogBRWorldManager') return;\n\n const ok = match.groups.data.match(/^World files saved after /);\n const err = match.groups.data.match(\n /^Error: (Invalid preset|World already exists|Failed to create new world)?/,\n );\n return ok ? { res: true } : err ? { res: false } : undefined;\n },\n {\n exec: () => {\n this.writeln(\n `${this.Console.World.CreateEmpty} \"${worldName}\" ${map}`,\n );\n },\n timeoutDelay: 2000,\n },\n );\n return match?.[0]?.['res'] ?? false;\n } catch (err) {\n return false;\n }\n }\n\n writeSaveData(saveName: string, saveData: WriteSaveObject) {\n if (typeof saveName !== 'string')\n throw 'expected name argument for writeSaveData';\n\n const file = join(this.savePath, saveName + '.brs');\n if (!file.startsWith(this.savePath))\n throw 'save file not in Saved/Builds directory';\n writeFileSync(file, new Uint8Array(brs.write(saveData)));\n }\n\n readSaveData(saveName: string, nobricks = false): ReadSaveObject {\n if (typeof saveName !== 'string')\n throw 'expected name argument for readSaveData';\n\n // EA3: the legacy .brs format is gone; saved builds are `.brz` prefabs.\n // Read the named prefab and reconstruct a legacy save object, mirroring\n // getSaveData's EA3 path.\n if (brsRemoved(this.version)) {\n const file = this.getPrefabPath(saveName);\n if (!file || !file.startsWith(this.prefabPath))\n throw 'prefab file not in Saved/Prefabs directory';\n return readPrefabData(this, file, { nobricks });\n }\n\n const file = this.getSavePath(saveName);\n if (!file || !file.startsWith(this.savePath))\n throw 'save file not in Saved/Builds directory';\n if (file)\n return brs.read(readFileSync(file), {\n preview: false,\n bricks: !nobricks,\n });\n }\n\n async loadSaveData(\n saveData: WriteSaveObject,\n {\n offX = 0,\n offY = 0,\n offZ = 0,\n quiet = false,\n correctPalette = false,\n correctCustom = false,\n } = {},\n ) {\n // EA3: the legacy Bricks.Load command was removed. Convert the save to a\n // .brz prefab and load it into the world via br.Prefab.Load. The palette\n // correction flags have no prefab equivalent and are ignored.\n if (brsRemoved(this.version)) {\n const { ref, file } = writeTempPrefab(this, saveData);\n this.loadPrefab(ref, { offX, offY, offZ });\n // the server reads the prefab synchronously and auto-closes the bundle a\n // couple seconds later; clean up the temp file lazily (cf. loadEnvironment)\n setTimeout(() => {\n if (existsSync(file)) unlinkSync(file);\n }, 5000);\n return;\n }\n\n const saveFile =\n this._tempSavePrefix + Date.now() + '_' + this._tempCounter.save++;\n // write savedata to file\n this.writeSaveData(saveFile, saveData);\n\n // wait for the server to finish reading the save\n await this.watchLogChunk(\n `${this.Console.Bricks.Load} \"${saveFile}\" ${offX} ${offY} ${offZ} ${quiet ? 1 : 0} ${\n correctPalette ? 1 : 0\n } ${correctCustom ? 1 : 0}`,\n /^LogBrickSerializer: (.+)$/,\n {\n first: match => match[0].endsWith(saveFile + '.brs...'),\n last: match => Boolean(match[1].match(/Read .+ bricks/)),\n afterMatchDelay: 0,\n timeoutDelay: 30000,\n },\n );\n\n // delete the save file after we're done\n const savePath = this.getSavePath(saveFile);\n if (savePath) {\n unlinkSync(savePath);\n }\n }\n\n async loadSaveDataOnPlayer(\n saveData: WriteSaveObject,\n player: string | OmeggaPlayer,\n {\n offX = 0,\n offY = 0,\n offZ = 0,\n correctPalette = false,\n correctCustom = false,\n } = {},\n ) {\n player = typeof player === 'string' ? this.getPlayer(player) : player;\n if (!player) return;\n\n // EA3: give the save to the player as a prefab (their inventory) via\n // br.Prefab.GiveToPlayer. Offsets have no equivalent and are ignored,\n // matching loadPrefabOnPlayer.\n if (brsRemoved(this.version)) {\n const { ref, file } = writeTempPrefab(this, saveData);\n this.givePrefabToPlayer(ref, player);\n setTimeout(() => {\n if (existsSync(file)) unlinkSync(file);\n }, 5000);\n return;\n }\n\n // The Bricks.LoadTemplate command was removed at EA2, before the prefab\n // commands existed; there is no working path on that intermediate version.\n if (\n warnRemoved(\n this.version,\n 'loadSaveDataOnPlayer',\n EA2_VERSION,\n 'EA2',\n 'loadPrefabOnPlayer',\n )\n )\n return;\n\n const saveFile =\n this._tempSavePrefix + Date.now() + '_' + this._tempCounter.save++;\n // write savedata to file\n this.writeSaveData(saveFile, saveData);\n\n // wait for the server to finish reading the save\n await this.watchLogChunk(\n `${this.Console.Bricks.LoadTemplate} \"${saveFile}\" ${offX} ${offY} ${offZ} ${\n correctPalette ? 1 : 0\n } ${correctCustom ? 1 : 0} \"${player.name}\"`,\n /^LogBrickSerializer: (.+)$/,\n {\n first: match => match[0].endsWith(saveFile + '.brs...'),\n last: match => Boolean(match[1].match(/Read .+ bricks/)),\n afterMatchDelay: 0,\n timeoutDelay: 30000,\n },\n );\n\n // delete the save file after we're done\n const savePath = this.getSavePath(saveFile);\n if (savePath) {\n unlinkSync(savePath);\n }\n }\n\n async getSaveData(region?: {\n center: [number, number, number];\n extent: [number, number, number];\n }) {\n // EA3: the legacy Bricks.Save command was removed. Save the world (or the\n // requested region) as a .brz prefab, then read it back into a legacy save\n // object. Brick geometry, ownership, assets, materials, colors, and\n // components are reconstructed; wires are not (the save-level `wires`\n // array is left empty). Component names/data are EA3-native (e.g.\n // `Component_Internal_Seat`), not the legacy `BCD_*` names.\n if (brsRemoved(this.version)) {\n const ref =\n this._tempSavePrefix + Date.now() + '_' + this._tempCounter.save++;\n const file = await this.savePrefabAsync(ref, { region });\n if (!file) return undefined;\n\n try {\n return readPrefabData(this, file);\n } finally {\n if (existsSync(file)) unlinkSync(file);\n }\n }\n\n const saveFile =\n this._tempSavePrefix + Date.now() + '_' + this._tempCounter.save++;\n\n await this.saveBricksAsync(saveFile, region);\n\n // read the save file\n const savePath = this.getSavePath(saveFile);\n if (savePath) {\n // read and parse the save file\n const saveData = brs.read(readFileSync(savePath));\n\n // delete the save file after we're done reading it\n unlinkSync(savePath);\n\n // return the parsed save\n return saveData;\n }\n\n return undefined;\n }\n\n /**\n * Load a prefab into the world (EA3). `path` is a bundle\n * path ref such as `Prefabs/Uploads/<hash>.brz`.\n * br.Prefab.Load <Path> [Offset X Y Z] [At Original Position] [Orientation]\n * [Root Entity Persistent Index] [Mirror Axes] [Override User Id]\n */\n loadPrefab(\n path: string,\n {\n offX = 0,\n offY = 0,\n offZ = 0,\n atOriginalPosition = false,\n orientation = 0,\n rootEntityPersistentIndex = -1,\n mirrorAxes = 0,\n overrideUserId = '',\n }: {\n offX?: number;\n offY?: number;\n offZ?: number;\n atOriginalPosition?: boolean;\n orientation?: number;\n rootEntityPersistentIndex?: number;\n /** bitmask: X=1 Y=2 Z=4 (e.g. 3 mirrors X and Y) */\n mirrorAxes?: number;\n overrideUserId?: string;\n } = {},\n ) {\n if (!path) return;\n // The root entity persistent index is looked up as a literal brick-grid\n // entity, so passing the -1 sentinel errors (\"No brick grid entity with\n // persistent index 4294967295\"). Omit it (and the positional args after\n // it) to load into the world grid; only include it when a real index is\n // given.\n const rootPart =\n rootEntityPersistentIndex >= 0\n ? ` ${rootEntityPersistentIndex} ${mirrorAxes}${\n overrideUserId ? ` \"${overrideUserId}\"` : ''\n }`\n : '';\n this.writeln(\n `${this.Console.Prefab.Load} \"${path}\" ${offX} ${offY} ${offZ} ${\n atOriginalPosition ? 1 : 0\n } ${orientation}${rootPart}`,\n );\n }\n\n /**\n * Load a prefab onto a player (EA3). Replaces the\n * removed {@link loadBricksOnPlayer}; backed by `br.Prefab.GiveToPlayer`.\n * @param path prefab bundle path ref\n * @param player player name/id or player object\n * @param options give options (preserve ownership)\n */\n loadPrefabOnPlayer(\n path: string,\n player: string | OmeggaPlayer,\n { preserveOwnership = false }: { preserveOwnership?: boolean } = {},\n ) {\n this.givePrefabToPlayer(path, player, { preserveOwnership });\n }\n\n /**\n * Save the world (or a region of it) as a prefab (EA3).\n * `path` is the destination bundle path ref (e.g. `Prefabs/MyPrefab.brz`).\n * br.Prefab.SaveRegion <Path> <Center X Y Z> <Extent X Y Z> [Include Entities]\n * [Root Entity Persistent Index] [Filter User Id]\n * @param path destination prefab bundle path ref\n * @param options save options; omit `region` to capture the whole world\n */\n savePrefab(\n path: string,\n {\n region,\n entities = true,\n rootEntityPersistentIndex = -1,\n userId = '',\n }: {\n region?: {\n center: [number, number, number];\n extent: [number, number, number];\n };\n entities?: boolean;\n rootEntityPersistentIndex?: number;\n userId?: string;\n } = {},\n ) {\n if (!path) return;\n // the command always takes a region; with none given, capture the whole\n // world from the origin with a maximal extent\n const center = (region?.center ?? [0, 0, 0]).join(' ');\n const extent = (\n region?.extent ?? [\n WHOLE_WORLD_EXTENT,\n WHOLE_WORLD_EXTENT,\n WHOLE_WORLD_EXTENT,\n ]\n ).join(' ');\n // As in loadPrefab, the root entity persistent index is looked up as a\n // literal brick-grid entity, so passing the -1 sentinel fails with\n // \"No brick grid entity with persistent index 4294967295\" and nothing is\n // written. Omit it (and the user id after it) to save from the world grid.\n const rootPart =\n rootEntityPersistentIndex >= 0\n ? ` ${rootEntityPersistentIndex}${userId ? ` \"${userId}\"` : ''}`\n : '';\n this.writeln(\n `${this.Console.Prefab.SaveRegion} \"${path}\" ${center} ${extent} ${\n entities ? 1 : 0\n }${rootPart}`,\n );\n }\n\n /**\n * Save a prefab and resolve once the prefab file has been written to disk.\n * @param path destination prefab bundle path ref\n * @param options same options as {@link savePrefab}\n * @returns the absolute path to the written prefab, or null on timeout\n */\n async savePrefabAsync(\n path: string,\n options?: {\n region?: {\n center: [number, number, number];\n extent: [number, number, number];\n };\n entities?: boolean;\n rootEntityPersistentIndex?: number;\n userId?: string;\n },\n ): Promise<string | null> {\n if (!path) return null;\n this.savePrefab(path, options);\n\n // TODO: confirm the write via the prefab-saved log line once its exact\n // format is nailed down; for now poll for the written file on disk.\n const name = path.replace(/^Prefabs[\\\\/]/i, '').replace(/\\.brz$/i, '');\n const file = join(this.prefabPath, name + '.brz');\n const deadline = Date.now() + 30000;\n while (Date.now() < deadline) {\n if (existsSync(file)) return file;\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n return null;\n }\n\n /**\n * Give a prefab to a player's inventory (EA3).\n * br.Prefab.GiveToPlayer <Path> <Player Name or User Id> [Preserve Ownership]\n */\n givePrefabToPlayer(\n path: string,\n player: string | OmeggaPlayer,\n { preserveOwnership = false }: { preserveOwnership?: boolean } = {},\n ) {\n if (!path) return;\n // the command accepts a player name or user id; prefer the resolved id\n const target = typeof player === 'object' ? player.id : player;\n if (!target) return;\n this.writeln(\n `${this.Console.Prefab.GiveToPlayer} \"${path}\" \"${target}\" ${\n preserveOwnership ? 1 : 0\n }`,\n );\n }\n\n // TODO: switch this to use worlds...\n async changeMap(map: string) {\n if (!map) return;\n\n // ServerTravel requires /Game/Maps/Plate/Plate instead of Plate\n const brName = mapUtils.n2brn(map);\n\n // wait for the server to change maps\n const match = await this.addWatcher(\n /^.*(LogLoad: Took .+ seconds to LoadMap\\((?<map>.+)\\))|(ERROR: The map .+)$/,\n {\n timeoutDelay: 30000,\n exec: () => this.writeln(`ServerTravel ${brName}`),\n },\n );\n const success = !!(\n match &&\n match[0] &&\n match[0].groups &&\n match[0].groups.map\n );\n return success;\n }\n\n async getPlugin(name: string): Promise<PluginInterop> {\n const plugin = this.pluginLoader.plugins.find(p => p.getName() === name);\n\n if (plugin) {\n return {\n name,\n documentation: plugin.getDocumentation(),\n loaded: plugin.isLoaded(),\n emitPlugin: (event: string, ...args: any[]) => {\n return plugin.emitPlugin(event, 'unsafe', args);\n },\n };\n } else {\n return null;\n }\n }\n}\n"],"names":["version","PREFAB_VERSION","Logger","file","resolve","sep","existsSync","WorldReader","readFileSync","join","mkdir","writeFileSync","writeBrzLegacy","OmeggaWrapper","VERSION","commandInjector","CONFIG_SAVED_DIR","DATA_PATH","Webserver","PluginLoader","MATCHERS","pattern","resolveConsoleCommands","index","unlinkSync","readBinaryVersion","CONFIG_AUTH_DIR","CONFIG_HOME","copyFiles","BRICKADIA_AUTH_FILES","readWatchedJSON","basename","path","uuid","EA2_VERSION","readBrdbRevisions","match","mapUtils","plugin"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omegga",
3
- "version": "1.10.1",
3
+ "version": "1.11.0",
4
4
  "description": "Brickadia server installer, updater, manager, wrapper, configurator, and automator",
5
5
  "engines": {
6
6
  "node": ">=23.0.0"