omegga 1.4.0 → 1.5.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/.claude/settings.local.json +39 -0
- package/CHANGELOG.md +690 -0
- package/README.md +23 -2
- package/bin/omegga +1 -1
- package/dist/brickadia/server.js +1 -1
- package/dist/brickadia/server.js.map +1 -1
- package/dist/cli/terminal.js +47 -13
- package/dist/cli/terminal.js.map +1 -1
- package/dist/config/index.js +6 -0
- package/dist/config/index.js.map +1 -1
- package/dist/config/types.js +51 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config/validator.js +8 -20
- package/dist/config/validator.js.map +1 -1
- package/dist/index.js +12 -6
- package/dist/index.js.map +1 -1
- package/dist/logger.js +38 -8
- package/dist/logger.js.map +1 -1
- package/dist/main.js +27 -1
- package/dist/main.js.map +1 -1
- package/dist/omegga/matchers/command.js +10 -0
- package/dist/omegga/matchers/command.js.map +1 -1
- package/dist/omegga/plugin/plugin_node_unsafe.js +6 -0
- package/dist/omegga/plugin/plugin_node_unsafe.js.map +1 -1
- package/dist/omegga/server.js +51 -5
- package/dist/omegga/server.js.map +1 -1
- package/dist/omegga/wrapper.js +1 -0
- package/dist/omegga/wrapper.js.map +1 -1
- package/dist/plugin.js +1 -2
- package/dist/plugin.js.map +1 -1
- package/dist/updater/steam.js +175 -68
- package/dist/updater/steam.js.map +1 -1
- package/dist/util/brick/checkBounds.js +1 -2
- package/dist/util/brick/checkBounds.js.map +1 -1
- package/dist/util/brick/displayName.js +1 -2
- package/dist/util/brick/displayName.js.map +1 -1
- package/dist/util/brick/getBounds.js +1 -2
- package/dist/util/brick/getBounds.js.map +1 -1
- package/dist/util/brick/getBrickSize.js +1 -2
- package/dist/util/brick/getBrickSize.js.map +1 -1
- package/dist/util/brick/getScaleAxis.js +1 -2
- package/dist/util/brick/getScaleAxis.js.map +1 -1
- package/dist/util/brick/setOwnership.js +1 -2
- package/dist/util/brick/setOwnership.js.map +1 -1
- package/dist/webserver/backend/database.js +5 -3
- package/dist/webserver/backend/database.js.map +1 -1
- package/dist/webserver/backend/events.js +7 -0
- package/dist/webserver/backend/events.js.map +1 -0
- package/dist/webserver/backend/index.js +64 -26
- package/dist/webserver/backend/index.js.map +1 -1
- package/dist/webserver/backend/metrics.js +122 -11
- package/dist/webserver/backend/metrics.js.map +1 -1
- package/dist/webserver/backend/router/chat.js +58 -0
- package/dist/webserver/backend/router/chat.js.map +1 -0
- package/dist/webserver/backend/router/index.js +23 -0
- package/dist/webserver/backend/router/index.js.map +1 -0
- package/dist/webserver/backend/router/player.js +248 -0
- package/dist/webserver/backend/router/player.js.map +1 -0
- package/dist/webserver/backend/router/plugin.js +150 -0
- package/dist/webserver/backend/router/plugin.js.map +1 -0
- package/dist/webserver/backend/router/role.js +17 -0
- package/dist/webserver/backend/router/role.js.map +1 -0
- package/dist/webserver/backend/router/server.js +181 -0
- package/dist/webserver/backend/router/server.js.map +1 -0
- package/dist/webserver/backend/router/session.js +33 -0
- package/dist/webserver/backend/router/session.js.map +1 -0
- package/dist/webserver/backend/router/user.js +93 -0
- package/dist/webserver/backend/router/user.js.map +1 -0
- package/dist/webserver/backend/router/world.js +139 -0
- package/dist/webserver/backend/router/world.js.map +1 -0
- package/dist/webserver/backend/trpc.js +48 -0
- package/dist/webserver/backend/trpc.js.map +1 -0
- package/dist/webserver/backend/util.js +18 -0
- package/dist/webserver/backend/util.js.map +1 -1
- package/package.json +10 -5
- package/public/app.html +122 -4
- package/public/assets/IconWorldPlus-Dkos72Ws.js +2 -0
- package/public/assets/IconWorldPlus-Dkos72Ws.js.map +1 -0
- package/public/assets/app-CLZ-5FIi.js +6 -0
- package/public/assets/app-CLZ-5FIi.js.map +1 -0
- package/public/assets/client-BT1QYH0O.js.map +1 -1
- package/public/assets/index-DLZ8-XzO.js +4 -0
- package/public/assets/index-DLZ8-XzO.js.map +1 -0
- package/public/assets/shared/@components-DPHARroA.js +2 -0
- package/public/assets/shared/@components-DPHARroA.js.map +1 -0
- package/public/assets/shared/@tabler_icons-react-iQk11eD_.js +3 -0
- package/public/assets/shared/{@tabler_icons-react-B4bN8gHc.js.map → @tabler_icons-react-iQk11eD_.js.map} +1 -1
- package/public/auth.html +13 -1
- package/dist/info/default_commands.json.js +0 -39
- package/dist/info/default_commands.json.js.map +0 -1
- package/dist/webserver/backend/api.js +0 -797
- package/dist/webserver/backend/api.js.map +0 -1
- package/public/assets/IconWorldPlus-DpfueG8_.js +0 -2
- package/public/assets/IconWorldPlus-DpfueG8_.js.map +0 -1
- package/public/assets/app-nJIpyOiP.js +0 -6
- package/public/assets/app-nJIpyOiP.js.map +0 -1
- package/public/assets/index-3dNmNZ9B.js +0 -10
- package/public/assets/index-3dNmNZ9B.js.map +0 -1
- package/public/assets/shared/@components-DdtLZOaA.js +0 -2
- package/public/assets/shared/@components-DdtLZOaA.js.map +0 -1
- package/public/assets/shared/@tabler_icons-react-B4bN8gHc.js +0 -3
package/README.md
CHANGED
|
@@ -253,6 +253,15 @@ server:
|
|
|
253
253
|
# Specifying a branch will use the old launcher instead of SteamCMD
|
|
254
254
|
# This does not have full auto-updater support yet, though the game will update every time it is restarted
|
|
255
255
|
# branch: release:release-server
|
|
256
|
+
terminal:
|
|
257
|
+
# prepend timestamps to terminal output using dateformat syntax
|
|
258
|
+
# see https://www.npmjs.com/package/dateformat for format options
|
|
259
|
+
# timestamp: "HH:MM:ss" # 14:05:30
|
|
260
|
+
# timestamp: "yyyy-mm-dd" # 2026-03-10
|
|
261
|
+
# timestamp: "yyyy-mm-dd HH:MM:ss" # 2026-03-10 14:05:30
|
|
262
|
+
# timestamp: "HH:MM" # 14:05
|
|
263
|
+
# timestamp: "hh:MM:ss TT" # 02:05:30 PM
|
|
264
|
+
# timestamp: "[HH:MM:ss]" # [14:05:30]
|
|
256
265
|
```
|
|
257
266
|
|
|
258
267
|
Note: `BRANCH-server` branches download only server data
|
|
@@ -731,6 +740,8 @@ Cleanup is important as code can still be running after the plugin is unloaded r
|
|
|
731
740
|
|
|
732
741
|
Register custom `/commands` by returning `{registeredCommands: ['foo', 'bar']}` (registers command `/foo` and `/bar`) in the `async init()` method.
|
|
733
742
|
|
|
743
|
+
By defining an `async pluginEvent(event, from, ...args)` method in your plugin class, you can respond to events from other plugins, where `from` is the name of the other plugin, `event` is the name of the custom event, and `args` is an array of any passed arguments.
|
|
744
|
+
|
|
734
745
|
### Globals
|
|
735
746
|
|
|
736
747
|
- `OMEGGA_UTIL` - access to the `src/util/index.js` module
|
|
@@ -770,6 +781,13 @@ class PluginName {
|
|
|
770
781
|
.removeAllListeners('chatcmd:ping')
|
|
771
782
|
.removeAllListeners('chatcmd:pos');
|
|
772
783
|
}
|
|
784
|
+
|
|
785
|
+
// optional: respond to events from other plugins
|
|
786
|
+
async pluginEvent(event, from, ...args) {
|
|
787
|
+
if (event === 'greeting') {
|
|
788
|
+
return `Hello from ${from}!`;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
773
791
|
}
|
|
774
792
|
|
|
775
793
|
module.exports = PluginName;
|
|
@@ -1042,8 +1060,8 @@ These can be set in your shell or in a `.env` file the same directory as a `omeg
|
|
|
1042
1060
|
- `BRICKADIA_DIR` - Override the need to use steamcmd and point to a Brickadia install directory (eg. `/home/<USER>/.config/omegga/steam_installs/main/Brickadia`)
|
|
1043
1061
|
- `STEAM_INSTALLS_DIR` - Set where omegga installs brickadia via steamcmd (default `~/.config/omegga/steam_installs`)
|
|
1044
1062
|
- `STEAM_APP_ID` - Set the Steam App ID for Brickadia (default `3017590`)
|
|
1045
|
-
- `STEAM_USERNAME` - Set the Steam username for downloading Brickadia via steamcmd
|
|
1046
|
-
- `STEAM_PASSWORD` -
|
|
1063
|
+
- `STEAM_USERNAME` - Set the Steam username for downloading Brickadia via steamcmd. Run `omegga steamlogin` to authenticate with Steam Guard
|
|
1064
|
+
- `STEAM_PASSWORD` - (Optional) Steam password; if not set, you will be prompted interactively
|
|
1047
1065
|
- `VERBOSE` - Set to `true` to enable verbose logging (default `false`)
|
|
1048
1066
|
- `PACKAGE_NOTIFIER` - When set to `false`, disables the npm update notifier
|
|
1049
1067
|
- `STEAM_NOTIFIER` - When set to `false`, disables the SteamCMD update notifier
|
|
@@ -1067,4 +1085,7 @@ server:
|
|
|
1067
1085
|
# When branch is present, steamcmd is not used
|
|
1068
1086
|
#branch: release:release-server # branch alias:branch name
|
|
1069
1087
|
steambeta: public # try `unstable`
|
|
1088
|
+
terminal:
|
|
1089
|
+
# prepend timestamps to terminal output (see https://www.npmjs.com/package/dateformat)
|
|
1090
|
+
#timestamp: "HH:MM:ss" # e.g. 14:05:30, "[HH:MM:ss]" for [14:05:30]
|
|
1070
1091
|
```
|
package/bin/omegga
CHANGED
package/dist/brickadia/server.js
CHANGED
|
@@ -205,7 +205,7 @@ class BrickadiaServer extends EventEmitter {
|
|
|
205
205
|
].filter(Boolean);
|
|
206
206
|
logger.default.verbose(
|
|
207
207
|
"Params for spawn",
|
|
208
|
-
params.join(" ").replace(/-User=".*?"/, '-User="<hidden>"').replace(/-Password=".*?"/, '-Password="<hidden>"').replace(/-Token=".*?"/, '-Token="<hidden>"')
|
|
208
|
+
params.join(" ").replace(/-User=".*?"/, '-User="<hidden>"').replace(/-Password=".*?"/, '-Password="<hidden>"').replace(/-Token=".*?"/, '-Token="<hidden>"').replace(/-Cookie=".*?"/, '-Cookie="<hidden>"').replace(/-Cookie=\S+/, "-Cookie=<hidden>")
|
|
209
209
|
);
|
|
210
210
|
this.#child = node_child_process.spawn("stdbuf", params);
|
|
211
211
|
logger.default.verbose(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sources":["../../src/brickadia/server.ts"],"sourcesContent":["/*\n Brickadia Server Wrapper\n Manages IO with the game server\n*/\n\nimport Logger from '@/logger';\nimport {\n ACTIVE_WORLD_FILE,\n CONFIG_SAVED_DIR,\n GAME_BIN_PATH,\n getOverrideGameBinary,\n getSteamGameDir,\n getSteamInstallDir,\n} from '@/softconfig';\nimport { getGlobalToken } from '@cli/auth';\nimport { IConfig } from '@config/types';\nimport { checkWsl } from '@util/wsl';\nimport 'colors';\nimport { ChildProcessWithoutNullStreams, spawn } from 'node:child_process';\nimport EventEmitter from 'node:events';\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { env } from 'node:process';\nimport readline from 'readline';\nimport stripAnsi from 'strip-ansi';\n\n// list of errors that can be solved by yelling at the user\nconst knownErrors: {\n name: string;\n solution?: string;\n match: RegExp;\n message?: string;\n}[] = [\n {\n name: 'MISSING_LIBGL',\n solution: 'apt-get install libgl1-mesa-glx libglib2.0-0',\n match:\n /error while loading shared libraries: libGL\\.so\\.1: cannot open shared object file/,\n },\n {\n name: 'MISSING_GLIB',\n solution: 'apt-get install libgl1-mesa-glx libglib2.0-0',\n match:\n /error while loading shared libraries: libgthread-2\\.0\\.so\\.0: cannot open shared object file/,\n },\n];\n\n/** Start a brickadia server */\nexport default class BrickadiaServer extends EventEmitter {\n #child: ChildProcessWithoutNullStreams = null;\n #errInterface: readline.Interface = null;\n #outInterface: readline.Interface = null;\n\n config: IConfig;\n path: string;\n\n constructor(dataPath: string, config: IConfig) {\n super();\n\n this.config = config;\n // use the data path if it's absolute, otherwise build an absolute path\n this.path =\n path.isAbsolute(dataPath) || dataPath.startsWith('/')\n ? dataPath\n : path.join(process.cwd(), dataPath);\n\n this.lineListener = this.lineListener.bind(this);\n this.errorListener = this.errorListener.bind(this);\n this.exitListener = this.exitListener.bind(this);\n }\n\n getActiveWorldFile(): string {\n return path.join(this.path, ACTIVE_WORLD_FILE);\n }\n\n /** A world specified by the active world file */\n getActiveWorld(): string | null {\n const activeWorldFile = this.getActiveWorldFile();\n if (existsSync(activeWorldFile)) {\n try {\n return readFileSync(activeWorldFile, 'utf8').trim();\n } catch (err) {\n Logger.errorp(\n 'Failed to read active world file',\n activeWorldFile.yellow,\n err,\n );\n return null;\n }\n }\n return null;\n }\n\n /** Set the world to use next startup */\n setActiveWorld(world: string | null): boolean {\n const activeWorldFile = this.getActiveWorldFile();\n if (!world || world === null) {\n if (existsSync(activeWorldFile)) {\n Logger.verbose('Removing active world file', activeWorldFile.yellow);\n unlinkSync(activeWorldFile);\n }\n return true;\n }\n\n if (!this.worldExists(world)) {\n Logger.verbose(\n 'Cannot set active world to',\n world.yellow,\n 'as it does not exist',\n );\n return false;\n }\n\n Logger.verbose('Setting active world to', world.yellow);\n try {\n writeFileSync(activeWorldFile, world, 'utf8');\n return true;\n } catch (err) {\n Logger.errorp(\n 'Failed to write active world file',\n activeWorldFile.yellow,\n err,\n );\n return false;\n }\n }\n\n /** A world specified by the config */\n getConfigWorld(): string | null {\n return this.config?.server?.world ?? null;\n }\n\n /** A world specified by the BRICKADIA_WORLD env variable */\n getEnvWorld(): string | null {\n return env.BRICKADIA_WORLD || null;\n }\n\n /** Check if a world exists */\n worldExists(world: string): boolean {\n const savedDir = this.config?.server?.savedDir ?? CONFIG_SAVED_DIR;\n const worldPath = path.join(this.path, savedDir, 'Worlds', world + '.brdb');\n return existsSync(worldPath);\n }\n\n /** Get the world that will be used next startup */\n getNextWorld() {\n const candidates = [\n { source: 'file', file: this.getActiveWorld() },\n { source: 'config', file: this.getConfigWorld() },\n { source: 'env', file: this.getEnvWorld() },\n ];\n\n return (\n candidates.find(({ file }) => file && this.worldExists(file)) ?? null\n );\n }\n\n // start the server child process\n start() {\n const {\n email,\n password,\n token: confToken,\n }: { email?: string; password?: string; token?: string } = this.config\n .credentials || {};\n\n const token = confToken || process.env.BRICKADIA_TOKEN || getGlobalToken();\n\n if (token) {\n Logger.verbose('Starting server with hosting token');\n } else {\n Logger.verbose(\n 'Starting server',\n (!email && !password ? 'without' : 'with').yellow,\n 'credentials',\n );\n }\n\n const isSteam = !this.config.server.branch;\n const steamBeta = this.config.server.steambeta ?? 'main';\n const overrideBinary = getOverrideGameBinary();\n const steamBinary = path.join(\n getSteamInstallDir(), // steam install directory\n steamBeta, // steam beta branch (or main)\n getSteamGameDir(), // Brickadia\n GAME_BIN_PATH, // path to binary\n );\n\n let gameBinary = steamBinary;\n\n if (overrideBinary) {\n if (!existsSync(overrideBinary)) {\n Logger.error(\n 'Override binary',\n overrideBinary.yellow,\n 'does not exist!',\n );\n throw new Error(`Override binary ${overrideBinary} does not exist!`);\n }\n\n Logger.verbose(\n 'Using override binary',\n overrideBinary.yellow,\n 'instead of',\n steamBinary.yellow,\n );\n gameBinary = overrideBinary;\n } else if (isSteam) {\n Logger.verbose('Using steam binary', steamBeta.yellow);\n } else {\n Logger.verbose(\n 'Running',\n (this.config.server.__LOCAL\n ? path.join(__dirname, '../../tools/brickadia.sh')\n : 'brickadia launcher'\n ).yellow,\n );\n if (typeof this.config.server.branch === 'string')\n Logger.verbose('Using branch', this.config.server.branch.yellow);\n }\n\n // handle local launcher support\n const launchArgs = isSteam\n ? [gameBinary]\n : [\n this.config.server.__LOCAL\n ? path.join(__dirname, '../../tools/brickadia.sh')\n : 'brickadia',\n this.config.server.branch && `--branch=${this.config.server.branch}`,\n '--server',\n '--',\n ];\n\n const world = this.getNextWorld();\n if (world) {\n Logger.verbose(\n 'Using world',\n world.file.yellow,\n 'from',\n world.source.yellow,\n );\n } else if (this.config.server.map) {\n Logger.verbose('Using map', this.config.server.map.yellow, 'from config');\n }\n\n const params = [\n '--output=L',\n '--',\n ...launchArgs,\n !world &&\n this.config.server.map &&\n `-Environment=\"${this.config.server.map}\"`,\n world && `-World=\"${world.file}\"`,\n '-NotInstalled',\n '-log',\n checkWsl() === 1 ? '-OneThread' : null,\n this.path ? `-UserDir=\"${this.path}\"` : null,\n token ? `-Token=\"${token}\"` : null, // remove token argument if not provided\n !token && email ? `-User=\"${email}\"` : null, // remove email argument if not provided or token is provided\n !token && password ? `-Password=\"${password}\"` : null, // remove password argument if not provided or token is provided\n `-port=\"${this.config.server.port}\"`,\n this.config.server.launchArgs,\n ].filter(Boolean); // remove unused arguments\n Logger.verbose(\n 'Params for spawn',\n params\n .join(' ')\n .replace(/-User=\".*?\"/, '-User=\"<hidden>\"')\n .replace(/-Password=\".*?\"/, '-Password=\"<hidden>\"')\n .replace(/-Token=\".*?\"/, '-Token=\"<hidden>\"'),\n );\n\n // Either unbuffer or stdbuf must be used because brickadia's output is buffered\n // this means that multiple lines can be bundled together if the output buffer is not full\n // unfortunately without stdbuf or unbuffer, the output would not happen immediately\n this.#child = spawn('stdbuf', params);\n\n Logger.verbose(\n 'Spawn process',\n this.#child ? this.#child.pid : 'failed'.red,\n );\n\n this.#child.stdin.setDefaultEncoding('utf8');\n this.#outInterface = readline.createInterface({\n input: this.#child.stdout,\n terminal: false,\n });\n this.#errInterface = readline.createInterface({\n input: this.#child.stderr,\n terminal: false,\n });\n this.attachListeners();\n Logger.verbose('Attached listeners');\n }\n\n // write a string to the child process\n write(line: string) {\n if (line.length >= 512) {\n // show a warning\n Logger.warn(\n 'WARNING'.yellow,\n 'The following line was called and is',\n 'longer than allowed limit'.red,\n );\n Logger.warn(line.replace(/\\n$/, ''));\n // throw a fake error to get the line number\n try {\n throw new Error('Console Line Too Long');\n } catch (err) {\n Logger.warn(err);\n }\n return;\n }\n if (this.#child) {\n Logger.verbose('WRITE'.green, line.replace(/\\n$/, ''));\n this.#child.stdin.write(line);\n }\n }\n\n // write a line to the child process\n writeln(line: string) {\n this.write(line + '\\n');\n }\n\n // forcibly kills the server\n stop() {\n if (!this.#child) {\n Logger.verbose('Cannot stop server as no subprocess exists');\n return;\n }\n\n Logger.verbose('Forcibly stopping server');\n // kill the process\n this.#child.kill('SIGINT');\n\n // ...kill it again just to make sure it's dead\n spawn('kill', ['-9', this.#child.pid + '']);\n }\n\n // detaches listeners\n cleanup() {\n if (!this.#child) return;\n\n Logger.verbose('Cleaning up brickadia server');\n\n // detach listener\n this.detachListeners();\n\n this.#child = null;\n this.#outInterface = null;\n this.#errInterface = null;\n }\n\n // attaches proxy event listeners\n attachListeners() {\n this.#outInterface.on('line', this.lineListener);\n this.#errInterface.on('line', this.errorListener);\n this.#child.on('exit', this.exitListener);\n this.#child.on('close', () => {});\n }\n\n // removes previously attached proxy event listeners\n detachListeners() {\n this.#outInterface.off('line', this.lineListener);\n this.#errInterface.off('line', this.errorListener);\n this.#child.off('exit', this.exitListener);\n this.#child.removeAllListeners('close');\n }\n\n // -- listeners for basic events (line, err, exit)\n errorListener(line: string) {\n Logger.verbose('ERROR'.red, line);\n this.emit('err', line);\n for (const { match, solution, name, message } of knownErrors) {\n if (line.match(match)) {\n Logger.error(\n `Encountered ${name.red}. ${\n solution ? 'Known fix:\\n ' + solution : message || 'Unknown error.'\n }`,\n );\n }\n }\n }\n\n exitListener(...args: any[]) {\n Logger.verbose('Exit listener fired');\n this.emit('closed', ...args);\n this.cleanup();\n }\n\n lineListener(line: string) {\n this.emit('line', stripAnsi(line));\n }\n}\n"],"names":["ACTIVE_WORLD_FILE","existsSync","readFileSync","Logger","unlinkSync","writeFileSync","env","CONFIG_SAVED_DIR","getGlobalToken","getOverrideGameBinary","getSteamInstallDir","getSteamGameDir","GAME_BIN_PATH","checkWsl","spawn"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.js","sources":["../../src/brickadia/server.ts"],"sourcesContent":["/*\n Brickadia Server Wrapper\n Manages IO with the game server\n*/\n\nimport Logger from '@/logger';\nimport {\n ACTIVE_WORLD_FILE,\n CONFIG_SAVED_DIR,\n GAME_BIN_PATH,\n getOverrideGameBinary,\n getSteamGameDir,\n getSteamInstallDir,\n} from '@/softconfig';\nimport { getGlobalToken } from '@cli/auth';\nimport { IConfig } from '@config/types';\nimport { checkWsl } from '@util/wsl';\nimport 'colors';\nimport { ChildProcessWithoutNullStreams, spawn } from 'node:child_process';\nimport EventEmitter from 'node:events';\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { env } from 'node:process';\nimport readline from 'readline';\nimport stripAnsi from 'strip-ansi';\n\n// list of errors that can be solved by yelling at the user\nconst knownErrors: {\n name: string;\n solution?: string;\n match: RegExp;\n message?: string;\n}[] = [\n {\n name: 'MISSING_LIBGL',\n solution: 'apt-get install libgl1-mesa-glx libglib2.0-0',\n match:\n /error while loading shared libraries: libGL\\.so\\.1: cannot open shared object file/,\n },\n {\n name: 'MISSING_GLIB',\n solution: 'apt-get install libgl1-mesa-glx libglib2.0-0',\n match:\n /error while loading shared libraries: libgthread-2\\.0\\.so\\.0: cannot open shared object file/,\n },\n];\n\n/** Start a brickadia server */\nexport default class BrickadiaServer extends EventEmitter {\n #child: ChildProcessWithoutNullStreams = null;\n #errInterface: readline.Interface = null;\n #outInterface: readline.Interface = null;\n\n config: IConfig;\n path: string;\n\n constructor(dataPath: string, config: IConfig) {\n super();\n\n this.config = config;\n // use the data path if it's absolute, otherwise build an absolute path\n this.path =\n path.isAbsolute(dataPath) || dataPath.startsWith('/')\n ? dataPath\n : path.join(process.cwd(), dataPath);\n\n this.lineListener = this.lineListener.bind(this);\n this.errorListener = this.errorListener.bind(this);\n this.exitListener = this.exitListener.bind(this);\n }\n\n getActiveWorldFile(): string {\n return path.join(this.path, ACTIVE_WORLD_FILE);\n }\n\n /** A world specified by the active world file */\n getActiveWorld(): string | null {\n const activeWorldFile = this.getActiveWorldFile();\n if (existsSync(activeWorldFile)) {\n try {\n return readFileSync(activeWorldFile, 'utf8').trim();\n } catch (err) {\n Logger.errorp(\n 'Failed to read active world file',\n activeWorldFile.yellow,\n err,\n );\n return null;\n }\n }\n return null;\n }\n\n /** Set the world to use next startup */\n setActiveWorld(world: string | null): boolean {\n const activeWorldFile = this.getActiveWorldFile();\n if (!world || world === null) {\n if (existsSync(activeWorldFile)) {\n Logger.verbose('Removing active world file', activeWorldFile.yellow);\n unlinkSync(activeWorldFile);\n }\n return true;\n }\n\n if (!this.worldExists(world)) {\n Logger.verbose(\n 'Cannot set active world to',\n world.yellow,\n 'as it does not exist',\n );\n return false;\n }\n\n Logger.verbose('Setting active world to', world.yellow);\n try {\n writeFileSync(activeWorldFile, world, 'utf8');\n return true;\n } catch (err) {\n Logger.errorp(\n 'Failed to write active world file',\n activeWorldFile.yellow,\n err,\n );\n return false;\n }\n }\n\n /** A world specified by the config */\n getConfigWorld(): string | null {\n return this.config?.server?.world ?? null;\n }\n\n /** A world specified by the BRICKADIA_WORLD env variable */\n getEnvWorld(): string | null {\n return env.BRICKADIA_WORLD || null;\n }\n\n /** Check if a world exists */\n worldExists(world: string): boolean {\n const savedDir = this.config?.server?.savedDir ?? CONFIG_SAVED_DIR;\n const worldPath = path.join(this.path, savedDir, 'Worlds', world + '.brdb');\n return existsSync(worldPath);\n }\n\n /** Get the world that will be used next startup */\n getNextWorld() {\n const candidates = [\n { source: 'file', file: this.getActiveWorld() },\n { source: 'config', file: this.getConfigWorld() },\n { source: 'env', file: this.getEnvWorld() },\n ];\n\n return (\n candidates.find(({ file }) => file && this.worldExists(file)) ?? null\n );\n }\n\n // start the server child process\n start() {\n const {\n email,\n password,\n token: confToken,\n }: { email?: string; password?: string; token?: string } = this.config\n .credentials || {};\n\n const token = confToken || process.env.BRICKADIA_TOKEN || getGlobalToken();\n\n if (token) {\n Logger.verbose('Starting server with hosting token');\n } else {\n Logger.verbose(\n 'Starting server',\n (!email && !password ? 'without' : 'with').yellow,\n 'credentials',\n );\n }\n\n const isSteam = !this.config.server.branch;\n const steamBeta = this.config.server.steambeta ?? 'main';\n const overrideBinary = getOverrideGameBinary();\n const steamBinary = path.join(\n getSteamInstallDir(), // steam install directory\n steamBeta, // steam beta branch (or main)\n getSteamGameDir(), // Brickadia\n GAME_BIN_PATH, // path to binary\n );\n\n let gameBinary = steamBinary;\n\n if (overrideBinary) {\n if (!existsSync(overrideBinary)) {\n Logger.error(\n 'Override binary',\n overrideBinary.yellow,\n 'does not exist!',\n );\n throw new Error(`Override binary ${overrideBinary} does not exist!`);\n }\n\n Logger.verbose(\n 'Using override binary',\n overrideBinary.yellow,\n 'instead of',\n steamBinary.yellow,\n );\n gameBinary = overrideBinary;\n } else if (isSteam) {\n Logger.verbose('Using steam binary', steamBeta.yellow);\n } else {\n Logger.verbose(\n 'Running',\n (this.config.server.__LOCAL\n ? path.join(__dirname, '../../tools/brickadia.sh')\n : 'brickadia launcher'\n ).yellow,\n );\n if (typeof this.config.server.branch === 'string')\n Logger.verbose('Using branch', this.config.server.branch.yellow);\n }\n\n // handle local launcher support\n const launchArgs = isSteam\n ? [gameBinary]\n : [\n this.config.server.__LOCAL\n ? path.join(__dirname, '../../tools/brickadia.sh')\n : 'brickadia',\n this.config.server.branch && `--branch=${this.config.server.branch}`,\n '--server',\n '--',\n ];\n\n const world = this.getNextWorld();\n if (world) {\n Logger.verbose(\n 'Using world',\n world.file.yellow,\n 'from',\n world.source.yellow,\n );\n } else if (this.config.server.map) {\n Logger.verbose('Using map', this.config.server.map.yellow, 'from config');\n }\n\n const params = [\n '--output=L',\n '--',\n ...launchArgs,\n !world &&\n this.config.server.map &&\n `-Environment=\"${this.config.server.map}\"`,\n world && `-World=\"${world.file}\"`,\n '-NotInstalled',\n '-log',\n checkWsl() === 1 ? '-OneThread' : null,\n this.path ? `-UserDir=\"${this.path}\"` : null,\n token ? `-Token=\"${token}\"` : null, // remove token argument if not provided\n !token && email ? `-User=\"${email}\"` : null, // remove email argument if not provided or token is provided\n !token && password ? `-Password=\"${password}\"` : null, // remove password argument if not provided or token is provided\n `-port=\"${this.config.server.port}\"`,\n this.config.server.launchArgs,\n ].filter(Boolean); // remove unused arguments\n Logger.verbose(\n 'Params for spawn',\n params\n .join(' ')\n .replace(/-User=\".*?\"/, '-User=\"<hidden>\"')\n .replace(/-Password=\".*?\"/, '-Password=\"<hidden>\"')\n .replace(/-Token=\".*?\"/, '-Token=\"<hidden>\"')\n .replace(/-Cookie=\".*?\"/, '-Cookie=\"<hidden>\"')\n .replace(/-Cookie=\\S+/, '-Cookie=<hidden>'),\n );\n\n // Either unbuffer or stdbuf must be used because brickadia's output is buffered\n // this means that multiple lines can be bundled together if the output buffer is not full\n // unfortunately without stdbuf or unbuffer, the output would not happen immediately\n this.#child = spawn('stdbuf', params);\n\n Logger.verbose(\n 'Spawn process',\n this.#child ? this.#child.pid : 'failed'.red,\n );\n\n this.#child.stdin.setDefaultEncoding('utf8');\n this.#outInterface = readline.createInterface({\n input: this.#child.stdout,\n terminal: false,\n });\n this.#errInterface = readline.createInterface({\n input: this.#child.stderr,\n terminal: false,\n });\n this.attachListeners();\n Logger.verbose('Attached listeners');\n }\n\n // write a string to the child process\n write(line: string) {\n if (line.length >= 512) {\n // show a warning\n Logger.warn(\n 'WARNING'.yellow,\n 'The following line was called and is',\n 'longer than allowed limit'.red,\n );\n Logger.warn(line.replace(/\\n$/, ''));\n // throw a fake error to get the line number\n try {\n throw new Error('Console Line Too Long');\n } catch (err) {\n Logger.warn(err);\n }\n return;\n }\n if (this.#child) {\n Logger.verbose('WRITE'.green, line.replace(/\\n$/, ''));\n this.#child.stdin.write(line);\n }\n }\n\n // write a line to the child process\n writeln(line: string) {\n this.write(line + '\\n');\n }\n\n // forcibly kills the server\n stop() {\n if (!this.#child) {\n Logger.verbose('Cannot stop server as no subprocess exists');\n return;\n }\n\n Logger.verbose('Forcibly stopping server');\n // kill the process\n this.#child.kill('SIGINT');\n\n // ...kill it again just to make sure it's dead\n spawn('kill', ['-9', this.#child.pid + '']);\n }\n\n // detaches listeners\n cleanup() {\n if (!this.#child) return;\n\n Logger.verbose('Cleaning up brickadia server');\n\n // detach listener\n this.detachListeners();\n\n this.#child = null;\n this.#outInterface = null;\n this.#errInterface = null;\n }\n\n // attaches proxy event listeners\n attachListeners() {\n this.#outInterface.on('line', this.lineListener);\n this.#errInterface.on('line', this.errorListener);\n this.#child.on('exit', this.exitListener);\n this.#child.on('close', () => {});\n }\n\n // removes previously attached proxy event listeners\n detachListeners() {\n this.#outInterface.off('line', this.lineListener);\n this.#errInterface.off('line', this.errorListener);\n this.#child.off('exit', this.exitListener);\n this.#child.removeAllListeners('close');\n }\n\n // -- listeners for basic events (line, err, exit)\n errorListener(line: string) {\n Logger.verbose('ERROR'.red, line);\n this.emit('err', line);\n for (const { match, solution, name, message } of knownErrors) {\n if (line.match(match)) {\n Logger.error(\n `Encountered ${name.red}. ${\n solution ? 'Known fix:\\n ' + solution : message || 'Unknown error.'\n }`,\n );\n }\n }\n }\n\n exitListener(...args: any[]) {\n Logger.verbose('Exit listener fired');\n this.emit('closed', ...args);\n this.cleanup();\n }\n\n lineListener(line: string) {\n this.emit('line', stripAnsi(line));\n }\n}\n"],"names":["ACTIVE_WORLD_FILE","existsSync","readFileSync","Logger","unlinkSync","writeFileSync","env","CONFIG_SAVED_DIR","getGlobalToken","getOverrideGameBinary","getSteamInstallDir","getSteamGameDir","GAME_BIN_PATH","checkWsl","spawn"],"mappings":"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"}
|
package/dist/cli/terminal.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
+
const logger = require("../logger.js");
|
|
3
4
|
const steam = require("../updater/steam.js");
|
|
4
5
|
const chat = require("../util/chat.js");
|
|
5
6
|
const wsl = require("../util/wsl.js");
|
|
7
|
+
const events = require("../webserver/backend/events.js");
|
|
6
8
|
const readline = require("readline");
|
|
7
9
|
const plugin = require("./plugin.js");
|
|
8
10
|
let log, err, warn, info;
|
|
@@ -102,7 +104,7 @@ const COMMANDS = [
|
|
|
102
104
|
},
|
|
103
105
|
// Server controls
|
|
104
106
|
{
|
|
105
|
-
aliases: ["stop"],
|
|
107
|
+
aliases: ["stop", "exit", "quit", "close"],
|
|
106
108
|
desc: "stop the server and close Omegga",
|
|
107
109
|
async fn() {
|
|
108
110
|
log("Stopping server...");
|
|
@@ -141,7 +143,7 @@ const COMMANDS = [
|
|
|
141
143
|
}
|
|
142
144
|
log("Updating server...");
|
|
143
145
|
try {
|
|
144
|
-
steam.steamcmdDownloadGame({
|
|
146
|
+
await steam.steamcmdDownloadGame({
|
|
145
147
|
steambeta: this.omegga.config.server?.steambeta,
|
|
146
148
|
steambetaPassword: this.omegga.config.server?.steambetaPassword
|
|
147
149
|
});
|
|
@@ -155,6 +157,40 @@ const COMMANDS = [
|
|
|
155
157
|
}
|
|
156
158
|
}
|
|
157
159
|
},
|
|
160
|
+
{
|
|
161
|
+
aliases: ["updatecheck", "uc", "check"],
|
|
162
|
+
desc: "check if a Steam update is available. use /uc show for details",
|
|
163
|
+
fn(subcommand) {
|
|
164
|
+
if (!this.omegga.config.__STEAM) {
|
|
165
|
+
err(
|
|
166
|
+
"This command is only available when the server is installed via SteamCMD"
|
|
167
|
+
);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
log("Checking for updates...");
|
|
171
|
+
const result = steam.steamcmdCheckUpdate(this.omegga.config.server?.steambeta);
|
|
172
|
+
if (!result) {
|
|
173
|
+
err("Failed to check for updates.");
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const { local, remote, hasUpdate } = result;
|
|
177
|
+
if (hasUpdate === true) log("Update available!".green);
|
|
178
|
+
else if (hasUpdate === false) log("Up to date.".green);
|
|
179
|
+
else log("Could not determine update status.".yellow);
|
|
180
|
+
if (subcommand === "show") {
|
|
181
|
+
const branch = local.betaKey && local.betaKey !== "main" ? local.betaKey : "public";
|
|
182
|
+
const remoteBuild = remote?.branches?.[branch];
|
|
183
|
+
const remotePart = remoteBuild ? `BuildID ${remoteBuild.buildid}` + (remoteBuild.timeupdated ? ` (${new Date(Number(remoteBuild.timeupdated) * 1e3).toLocaleString()})` : "") : "unknown (private branch?)";
|
|
184
|
+
log(
|
|
185
|
+
[
|
|
186
|
+
` Local: BuildID ${local.buildId} (${local.installState})`,
|
|
187
|
+
` Remote: ${remotePart}`,
|
|
188
|
+
` Branch: ${local.betaKey ?? "public"}`
|
|
189
|
+
].join("\n")
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
},
|
|
158
194
|
{
|
|
159
195
|
aliases: ["kill"],
|
|
160
196
|
desc: "forcefully kill brickadia server process without closing omegga",
|
|
@@ -781,14 +817,12 @@ class Terminal {
|
|
|
781
817
|
this.log(`[${"SERVER".brightMagenta.underline}]: ${line}`);
|
|
782
818
|
if (this.omegga.webserver) {
|
|
783
819
|
const user = { name: "SERVER", id: "", web: true, color: "ff00ff" };
|
|
784
|
-
this.omegga.webserver.
|
|
785
|
-
"
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
user,
|
|
789
|
-
line
|
|
790
|
-
)
|
|
820
|
+
const chatLog = await this.omegga.webserver.database.addChatLog(
|
|
821
|
+
"msg",
|
|
822
|
+
user,
|
|
823
|
+
line
|
|
791
824
|
);
|
|
825
|
+
events.serverEvents.emit("chat", chatLog);
|
|
792
826
|
}
|
|
793
827
|
} else {
|
|
794
828
|
err(
|
|
@@ -803,28 +837,28 @@ class Terminal {
|
|
|
803
837
|
log(...args) {
|
|
804
838
|
process.stdout.clearLine(0);
|
|
805
839
|
process.stdout.cursorTo(0);
|
|
806
|
-
console.log(...args);
|
|
840
|
+
console.log(...logger.default.timestamped(args));
|
|
807
841
|
this.rl.prompt(true);
|
|
808
842
|
}
|
|
809
843
|
// let readline render a debug log without interrupting user input
|
|
810
844
|
debug(...args) {
|
|
811
845
|
process.stdout.clearLine(0);
|
|
812
846
|
process.stdout.cursorTo(0);
|
|
813
|
-
console.debug(...args);
|
|
847
|
+
console.debug(...logger.default.timestamped(args));
|
|
814
848
|
this.rl.prompt(true);
|
|
815
849
|
}
|
|
816
850
|
// let readline render a warning log without interrupting user input
|
|
817
851
|
warn(...args) {
|
|
818
852
|
process.stdout.clearLine(0);
|
|
819
853
|
process.stdout.cursorTo(0);
|
|
820
|
-
console.warn(...args);
|
|
854
|
+
console.warn(...logger.default.timestamped(args));
|
|
821
855
|
this.rl.prompt(true);
|
|
822
856
|
}
|
|
823
857
|
// let readline render an error log without interrupting user input
|
|
824
858
|
error(...args) {
|
|
825
859
|
process.stdout.clearLine(0);
|
|
826
860
|
process.stdout.cursorTo(0);
|
|
827
|
-
console.error(...args);
|
|
861
|
+
console.error(...logger.default.timestamped(args));
|
|
828
862
|
this.rl.prompt(true);
|
|
829
863
|
}
|
|
830
864
|
}
|
package/dist/cli/terminal.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminal.js","sources":["../../src/cli/terminal.ts"],"sourcesContent":["import { OmeggaPlayer } from '@/plugin';\nimport { steamcmdDownloadGame } from '@/updater';\nimport Omegga from '@omegga/server';\nimport { IOmeggaOptions } from '@omegga/types';\nimport { sanitize } from '@util/chat';\nimport { checkWsl } from '@util/wsl';\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'],\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 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: ['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\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\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 if (options.debug) this.log('::'.blue, l);\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 this.omegga.webserver.io\n .to('chat')\n .emit(\n 'chat',\n await this.omegga.webserver.database.addChatLog(\n 'msg',\n user,\n line,\n ),\n );\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(...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(...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(...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(...args);\n this.rl.prompt(true);\n }\n}\n"],"names":["steamcmdDownloadGame","plugin","install","world","wsl","checkWsl","c","sanitize"],"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 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 if a Steam update is available. use /uc show for details',\n 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 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 },\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\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 if (options.debug) this.log('::'.blue, l);\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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"}
|
package/dist/config/index.js
CHANGED
|
@@ -8,6 +8,7 @@ const format_js = require("./formats/format_js.js");
|
|
|
8
8
|
const format_yml = require("./formats/format_yml.js");
|
|
9
9
|
const reader = require("./reader.js");
|
|
10
10
|
const writer = require("./writer.js");
|
|
11
|
+
const types = require("./types.js");
|
|
11
12
|
const store = new Configstore(
|
|
12
13
|
softconfig.default.PROJECT_NAME,
|
|
13
14
|
{
|
|
@@ -42,6 +43,11 @@ const find = (dir = ".") => {
|
|
|
42
43
|
return void 0;
|
|
43
44
|
};
|
|
44
45
|
const index = { store, write, read, find, defaultConfig, formats };
|
|
46
|
+
exports.BrickadiaConfigSchema = types.BrickadiaConfigSchema;
|
|
47
|
+
exports.ConfigSchema = types.ConfigSchema;
|
|
48
|
+
exports.CredentialsSchema = types.CredentialsSchema;
|
|
49
|
+
exports.ServerConfigSchema = types.ServerConfigSchema;
|
|
50
|
+
exports.TerminalConfigSchema = types.TerminalConfigSchema;
|
|
45
51
|
exports.default = index;
|
|
46
52
|
exports.defaultConfig = defaultConfig;
|
|
47
53
|
exports.find = find;
|
package/dist/config/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/config/index.ts"],"sourcesContent":["import soft from '@/softconfig';\nimport Configstore from 'configstore';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport format_js from './formats/format_js';\nimport format_yaml from './formats/format_yml';\nimport reader from './reader';\nimport { IConfig, IConfigFormat } from './types';\nimport writer from './writer';\nexport * from './types';\n\nexport const store = new Configstore(\n soft.PROJECT_NAME,\n {\n defaultOmegga: '.',\n legacyBin: '',\n },\n {\n globalConfigPath: true,\n },\n);\n\n// find all format_EXT.js files in the formats path\nconst formats: IConfigFormat[] = [format_js, format_yaml];\n\n// create read/write funcs for the provided formats\nexport const defaultConfig: IConfig = {\n omegga: {\n webui: true,\n port: process.env.OMEGGA_PORT\n ? Number(process.env.OMEGGA_PORT)\n : soft.DEFAULT_PORT,\n https: true,\n },\n server: {\n port: process.env.BRICKADIA_PORT\n ? Number(process.env.BRICKADIA_PORT)\n : 7777,\n map: 'Plate',\n },\n};\n\n// Writes save data to a file\nexport const write = writer(formats);\n\n// reads save data from a file\nexport const read = reader(formats);\n\n// open config at a specified path\nexport const find = (dir = '.') => {\n // find the first config file matching these config file names\n for (const f of soft.CONFIG_FILENAMES) {\n for (const { extension } of formats) {\n const file = path.join(dir, f + '.' + extension);\n if (fs.existsSync(file)) return file;\n }\n }\n\n return undefined;\n};\n\nexport * from './types';\n\nexport default { store, write, read, find, defaultConfig, formats };\n"],"names":["soft","format_js","format_yaml","writer","reader"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/config/index.ts"],"sourcesContent":["import soft from '@/softconfig';\nimport Configstore from 'configstore';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport format_js from './formats/format_js';\nimport format_yaml from './formats/format_yml';\nimport reader from './reader';\nimport { IConfig, IConfigFormat } from './types';\nimport writer from './writer';\nexport * from './types';\n\nexport const store = new Configstore(\n soft.PROJECT_NAME,\n {\n defaultOmegga: '.',\n legacyBin: '',\n },\n {\n globalConfigPath: true,\n },\n);\n\n// find all format_EXT.js files in the formats path\nconst formats: IConfigFormat[] = [format_js, format_yaml];\n\n// create read/write funcs for the provided formats\nexport const defaultConfig: IConfig = {\n omegga: {\n webui: true,\n port: process.env.OMEGGA_PORT\n ? Number(process.env.OMEGGA_PORT)\n : soft.DEFAULT_PORT,\n https: true,\n },\n server: {\n port: process.env.BRICKADIA_PORT\n ? Number(process.env.BRICKADIA_PORT)\n : 7777,\n map: 'Plate',\n },\n};\n\n// Writes save data to a file\nexport const write = writer(formats);\n\n// reads save data from a file\nexport const read = reader(formats);\n\n// open config at a specified path\nexport const find = (dir = '.') => {\n // find the first config file matching these config file names\n for (const f of soft.CONFIG_FILENAMES) {\n for (const { extension } of formats) {\n const file = path.join(dir, f + '.' + extension);\n if (fs.existsSync(file)) return file;\n }\n }\n\n return undefined;\n};\n\nexport * from './types';\n\nexport default { store, write, read, find, defaultConfig, formats };\n"],"names":["soft","format_js","format_yaml","writer","reader"],"mappings":";;;;;;;;;;;AAWO,MAAM,QAAQ,IAAI;AAAA,EACvBA,WAAAA,QAAK;AAAA,EACL;AAAA,IACE,eAAe;AAAA,IACf,WAAW;AAAA,EAAA;AAAA,EAEb;AAAA,IACE,kBAAkB;AAAA,EAAA;AAEtB;AAGA,MAAM,UAA2B,CAACC,UAAAA,SAAWC,kBAAW;AAGjD,MAAM,gBAAyB;AAAA,EACpC,QAAQ;AAAA,IACN,OAAO;AAAA,IACP,MAAM,QAAQ,IAAI,cACd,OAAO,QAAQ,IAAI,WAAW,IAC9BF,WAAAA,QAAK;AAAA,IACT,OAAO;AAAA,EAAA;AAAA,EAET,QAAQ;AAAA,IACN,MAAM,QAAQ,IAAI,iBACd,OAAO,QAAQ,IAAI,cAAc,IACjC;AAAA,IACJ,KAAK;AAAA,EAAA;AAET;AAGO,MAAM,QAAQG,OAAAA,QAAO,OAAO;AAG5B,MAAM,OAAOC,OAAAA,QAAO,OAAO;AAG3B,MAAM,OAAO,CAAC,MAAM,QAAQ;AAEjC,aAAW,KAAKJ,WAAAA,QAAK,kBAAkB;AACrC,eAAW,EAAE,UAAA,KAAe,SAAS;AACnC,YAAM,OAAO,KAAK,KAAK,KAAK,IAAI,MAAM,SAAS;AAC/C,UAAI,GAAG,WAAW,IAAI,EAAG,QAAO;AAAA,IAClC;AAAA,EACF;AAEA,SAAO;AACT;AAIA,MAAA,QAAe,EAAE,OAAO,OAAO,MAAM,MAAM,eAAe,QAAA;;;;;;;;;;;;"}
|