@jpp-toolkit/plugin-build-fivem 0.0.2 → 0.0.4

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/dist/index.d.mts CHANGED
@@ -12,10 +12,14 @@ declare class FivemBuildCommand extends Command {
12
12
  password: _oclif_core_interfaces0.OptionFlag<string | undefined, _oclif_core_interfaces0.CustomOptions>;
13
13
  resourceName: _oclif_core_interfaces0.OptionFlag<string | undefined, _oclif_core_interfaces0.CustomOptions>;
14
14
  };
15
- static examples: never[];
15
+ static examples: {
16
+ description: string;
17
+ command: string;
18
+ }[];
16
19
  run(): Promise<void>;
17
20
  private _parseServerAddress;
18
21
  private _compilerCallback;
22
+ private _connectRcon;
19
23
  private _enableAutoReload;
20
24
  }
21
25
  //#endregion
package/dist/index.mjs CHANGED
@@ -4,7 +4,7 @@ import { createFivemRspackConfig } from "@jpp-toolkit/rspack-config";
4
4
  import { getErrMsg } from "@jpp-toolkit/utils";
5
5
  import { Flags } from "@oclif/core";
6
6
  import { rspack } from "@rspack/core";
7
- import { Rcon } from "rcon-client";
7
+ import Rcon from "rcon";
8
8
 
9
9
  //#region src/fivem-build-command.ts
10
10
  var FivemBuildCommand = class FivemBuildCommand extends Command {
@@ -43,7 +43,32 @@ var FivemBuildCommand = class FivemBuildCommand extends Command {
43
43
  required: false
44
44
  })
45
45
  };
46
- static examples = [];
46
+ static examples = [
47
+ {
48
+ description: "Build the FiveM resource.",
49
+ command: "<%= config.bin %> <%= command.id %>"
50
+ },
51
+ {
52
+ description: "Build the FiveM resource in watch mode.",
53
+ command: "<%= config.bin %> <%= command.id %> --watch"
54
+ },
55
+ {
56
+ description: "Build the FiveM resource in production mode.",
57
+ command: "<%= config.bin %> <%= command.id %> --mode=production"
58
+ },
59
+ {
60
+ description: "Build the FiveM resource and automatically reload it on the server after build.",
61
+ command: "<%= config.bin %> <%= command.id %> --auto-reload --password your_rcon_password"
62
+ },
63
+ {
64
+ description: "Build the FiveM resource in watch mode and automatically reload it on the server after each build.",
65
+ command: "<%= config.bin %> <%= command.id %> --watch --auto-reload --password your_rcon_password"
66
+ },
67
+ {
68
+ description: "Build the FiveM resource and connect to a specific server for auto-reload.",
69
+ command: "<%= config.bin %> <%= command.id %> --auto-reload --server=127.0.0.1:30120 --password your_rcon_password"
70
+ }
71
+ ];
47
72
  async run() {
48
73
  const { flags } = await this.parse(FivemBuildCommand);
49
74
  const { watch, autoReload, password } = flags;
@@ -52,16 +77,8 @@ var FivemBuildCommand = class FivemBuildCommand extends Command {
52
77
  const resourceName = flags.resourceName ?? path.basename(process.cwd());
53
78
  const compiler = rspack(createFivemRspackConfig({ mode }));
54
79
  if (autoReload) {
55
- if (!password) {
56
- this.logger.error("RCON password is required for auto-reload. Please provide it using the --password flag.");
57
- this.exit(1);
58
- }
59
- const rcon = new Rcon({
60
- host,
61
- port,
62
- password
63
- });
64
- await this._enableAutoReload(compiler, rcon, resourceName);
80
+ if (!password) this.fatalError("RCON password is required for auto-reload. Please provide it using the --password flag.");
81
+ await this._enableAutoReload(compiler, resourceName, host, port, password);
65
82
  }
66
83
  if (flags.watch) {
67
84
  this.logger.info(`Building FiveM resource in watch mode...\n`);
@@ -88,14 +105,32 @@ var FivemBuildCommand = class FivemBuildCommand extends Command {
88
105
  }
89
106
  if (stats) this.logger.log(stats.toString(), "\n");
90
107
  }
91
- async _enableAutoReload(compiler, rcon, resourceName) {
92
- compiler.hooks.done.tapPromise("FivemAutoReloadPlugin", async (stats) => {
108
+ async _connectRcon(host, port, password) {
109
+ return new Promise((resolve, reject) => {
110
+ const rcon = new Rcon(host, port, password, {
111
+ tcp: false,
112
+ challenge: false
113
+ });
114
+ rcon.on("auth", () => resolve(rcon));
115
+ rcon.on("error", reject);
116
+ rcon.on("end", () => reject(/* @__PURE__ */ new Error("RCON connection ended unexpectedly.")));
117
+ rcon.connect();
118
+ });
119
+ }
120
+ async _enableAutoReload(compiler, resourceName, host, port, password) {
121
+ const rcon = await this._connectRcon(host, port, password);
122
+ rcon.on("response", (res) => {
123
+ if (res.includes("Couldn't find resource")) this.fatalError("Couldn't find resource");
124
+ if (res === "rint Invalid password") this.fatalError("Invalid password");
125
+ });
126
+ compiler.hooks.done.tap("FivemAutoReloadPlugin", (stats) => {
93
127
  if (stats.hasErrors()) {
94
- this.logger.warning("Build failed. Skipping FiveM resource reload.");
128
+ this.logger.warning("Build failed. Skipping FiveM resource reload.\n");
95
129
  return;
96
130
  }
97
131
  this.logger.info(`Reloading FiveM resource "${resourceName}"...`);
98
132
  try {
133
+ rcon.send(`refresh; ensure ${resourceName}`);
99
134
  this.logger.success(`FiveM resource reloaded successfully.\n`);
100
135
  } catch (error) {
101
136
  this.logger.error(`Failed to reload FiveM resource: ${getErrMsg(error)}\n`);
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/fivem-build-command.ts","../src/index.ts"],"sourcesContent":["import path from 'node:path';\n\nimport { Command } from '@jpp-toolkit/core';\nimport { createFivemRspackConfig } from '@jpp-toolkit/rspack-config';\nimport { getErrMsg } from '@jpp-toolkit/utils';\nimport { Flags } from '@oclif/core';\nimport type { Compiler, Stats } from '@rspack/core';\nimport { rspack } from '@rspack/core';\nimport { Rcon } from 'rcon-client';\n\ntype Mode = 'development' | 'production';\ntype ServerAddress = { readonly host: string; readonly port: number };\n\nexport class FivemBuildCommand extends Command {\n static override summary = 'Build the FiveM resource using predefined config.';\n\n static override flags = {\n watch: Flags.boolean({\n char: 'w',\n description: 'Watch files for changes and rebuild automatically.',\n default: false,\n }),\n mode: Flags.string({\n char: 'm',\n description: 'Set the build mode (development or production).',\n options: ['development', 'production'],\n required: false,\n }),\n autoReload: Flags.boolean({\n char: 'r',\n description: 'Automatically reload FiveM resource after build.',\n default: false,\n }),\n server: Flags.string({\n char: 's',\n description: 'Server \"ip:port\" to connect for reloading FiveM resource after build.',\n default: '127.0.0.1:30120',\n required: false,\n }),\n password: Flags.string({\n char: 'p',\n description: 'RCON password for the FiveM server to reload resource after build.',\n required: false,\n }),\n resourceName: Flags.string({\n char: 'n',\n description:\n 'Name of the FiveM resource to reload. If not provided, the name of the folder containing the resource will be used.',\n required: false,\n }),\n };\n\n static override examples = [];\n\n public async run(): Promise<void> {\n const { flags } = await this.parse(FivemBuildCommand);\n\n const { watch, autoReload, password } = flags;\n const mode = (flags.mode ?? (watch ? 'development' : 'production')) as Mode;\n const { host, port } = this._parseServerAddress(flags.server);\n const resourceName = flags.resourceName ?? path.basename(process.cwd());\n\n const config = createFivemRspackConfig({ mode });\n const compiler = rspack(config);\n\n if (autoReload) {\n if (!password) {\n this.logger.error(\n 'RCON password is required for auto-reload. Please provide it using the --password flag.',\n );\n this.exit(1);\n }\n\n const rcon = new Rcon({ host, port, password });\n await this._enableAutoReload(compiler, rcon, resourceName);\n }\n\n if (flags.watch) {\n this.logger.info(`Building FiveM resource in watch mode...\\n`);\n compiler.watch({}, this._compilerCallback.bind(this));\n } else {\n this.logger.info(`Building FiveM resource...\\n`);\n compiler.run(this._compilerCallback.bind(this));\n }\n }\n\n private _parseServerAddress(address: string): ServerAddress {\n const match = /^(?<host>[^:]+):(?<port>\\d+)$/u.exec(address);\n const { host, port } = match?.groups ?? {};\n\n if (!host || !port) {\n throw new Error(\n `Invalid server address format: ${address}. Expected format is \"ip:port\".`,\n );\n }\n\n return { host, port: parseInt(port) };\n }\n\n private _compilerCallback(err: Error | null, stats: Stats | undefined): void {\n if (err) {\n this.logger.error(getErrMsg(err));\n if ('details' in err) this.logger.error(err.details as string);\n if ('stack' in err) this.logger.error(err.stack);\n return;\n }\n\n if (stats) this.logger.log(stats.toString(), '\\n');\n }\n\n private async _enableAutoReload(\n compiler: Compiler,\n rcon: Rcon,\n resourceName: string,\n ): Promise<void> {\n try {\n // await rcon.connect();\n } catch (error) {\n this.logger.error(`Failed to connect to FiveM server via RCON: ${getErrMsg(error)}`);\n this.exit(1);\n }\n\n compiler.hooks.done.tapPromise('FivemAutoReloadPlugin', async (stats) => {\n if (stats.hasErrors()) {\n this.logger.warning('Build failed. Skipping FiveM resource reload.');\n return;\n }\n\n this.logger.info(`Reloading FiveM resource \"${resourceName}\"...`);\n try {\n // await rcon.send(`refresh; ensure ${resourceName}`);\n this.logger.success(`FiveM resource reloaded successfully.\\n`);\n } catch (error) {\n this.logger.error(`Failed to reload FiveM resource: ${getErrMsg(error)}\\n`);\n }\n });\n }\n}\n","import { FivemBuildCommand } from './fivem-build-command';\n\nexport const commands = {\n 'build:fivem': FivemBuildCommand,\n};\n"],"mappings":";;;;;;;;;AAaA,IAAa,oBAAb,MAAa,0BAA0B,QAAQ;CAC3C,OAAgB,UAAU;CAE1B,OAAgB,QAAQ;EACpB,OAAO,MAAM,QAAQ;GACjB,MAAM;GACN,aAAa;GACb,SAAS;GACZ,CAAC;EACF,MAAM,MAAM,OAAO;GACf,MAAM;GACN,aAAa;GACb,SAAS,CAAC,eAAe,aAAa;GACtC,UAAU;GACb,CAAC;EACF,YAAY,MAAM,QAAQ;GACtB,MAAM;GACN,aAAa;GACb,SAAS;GACZ,CAAC;EACF,QAAQ,MAAM,OAAO;GACjB,MAAM;GACN,aAAa;GACb,SAAS;GACT,UAAU;GACb,CAAC;EACF,UAAU,MAAM,OAAO;GACnB,MAAM;GACN,aAAa;GACb,UAAU;GACb,CAAC;EACF,cAAc,MAAM,OAAO;GACvB,MAAM;GACN,aACI;GACJ,UAAU;GACb,CAAC;EACL;CAED,OAAgB,WAAW,EAAE;CAE7B,MAAa,MAAqB;EAC9B,MAAM,EAAE,UAAU,MAAM,KAAK,MAAM,kBAAkB;EAErD,MAAM,EAAE,OAAO,YAAY,aAAa;EACxC,MAAM,OAAQ,MAAM,SAAS,QAAQ,gBAAgB;EACrD,MAAM,EAAE,MAAM,SAAS,KAAK,oBAAoB,MAAM,OAAO;EAC7D,MAAM,eAAe,MAAM,gBAAgB,KAAK,SAAS,QAAQ,KAAK,CAAC;EAGvE,MAAM,WAAW,OADF,wBAAwB,EAAE,MAAM,CAAC,CACjB;AAE/B,MAAI,YAAY;AACZ,OAAI,CAAC,UAAU;AACX,SAAK,OAAO,MACR,0FACH;AACD,SAAK,KAAK,EAAE;;GAGhB,MAAM,OAAO,IAAI,KAAK;IAAE;IAAM;IAAM;IAAU,CAAC;AAC/C,SAAM,KAAK,kBAAkB,UAAU,MAAM,aAAa;;AAG9D,MAAI,MAAM,OAAO;AACb,QAAK,OAAO,KAAK,6CAA6C;AAC9D,YAAS,MAAM,EAAE,EAAE,KAAK,kBAAkB,KAAK,KAAK,CAAC;SAClD;AACH,QAAK,OAAO,KAAK,+BAA+B;AAChD,YAAS,IAAI,KAAK,kBAAkB,KAAK,KAAK,CAAC;;;CAIvD,AAAQ,oBAAoB,SAAgC;EAExD,MAAM,EAAE,MAAM,SADA,iCAAiC,KAAK,QAAQ,EAC9B,UAAU,EAAE;AAE1C,MAAI,CAAC,QAAQ,CAAC,KACV,OAAM,IAAI,MACN,kCAAkC,QAAQ,iCAC7C;AAGL,SAAO;GAAE;GAAM,MAAM,SAAS,KAAK;GAAE;;CAGzC,AAAQ,kBAAkB,KAAmB,OAAgC;AACzE,MAAI,KAAK;AACL,QAAK,OAAO,MAAM,UAAU,IAAI,CAAC;AACjC,OAAI,aAAa,IAAK,MAAK,OAAO,MAAM,IAAI,QAAkB;AAC9D,OAAI,WAAW,IAAK,MAAK,OAAO,MAAM,IAAI,MAAM;AAChD;;AAGJ,MAAI,MAAO,MAAK,OAAO,IAAI,MAAM,UAAU,EAAE,KAAK;;CAGtD,MAAc,kBACV,UACA,MACA,cACa;AAQb,WAAS,MAAM,KAAK,WAAW,yBAAyB,OAAO,UAAU;AACrE,OAAI,MAAM,WAAW,EAAE;AACnB,SAAK,OAAO,QAAQ,gDAAgD;AACpE;;AAGJ,QAAK,OAAO,KAAK,6BAA6B,aAAa,MAAM;AACjE,OAAI;AAEA,SAAK,OAAO,QAAQ,0CAA0C;YACzD,OAAO;AACZ,SAAK,OAAO,MAAM,oCAAoC,UAAU,MAAM,CAAC,IAAI;;IAEjF;;;;;;ACrIV,MAAa,WAAW,EACpB,eAAe,mBAClB"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/fivem-build-command.ts","../src/index.ts"],"sourcesContent":["import path from 'node:path';\n\nimport { Command } from '@jpp-toolkit/core';\nimport { createFivemRspackConfig } from '@jpp-toolkit/rspack-config';\nimport { getErrMsg } from '@jpp-toolkit/utils';\nimport { Flags } from '@oclif/core';\nimport type { Compiler, Stats } from '@rspack/core';\nimport { rspack } from '@rspack/core';\nimport Rcon from 'rcon';\n\ntype Mode = 'development' | 'production';\ntype ServerAddress = { readonly host: string; readonly port: number };\n\nexport class FivemBuildCommand extends Command {\n static override summary = 'Build the FiveM resource using predefined config.';\n\n static override flags = {\n watch: Flags.boolean({\n char: 'w',\n description: 'Watch files for changes and rebuild automatically.',\n default: false,\n }),\n mode: Flags.string({\n char: 'm',\n description: 'Set the build mode (development or production).',\n options: ['development', 'production'],\n required: false,\n }),\n autoReload: Flags.boolean({\n char: 'r',\n description: 'Automatically reload FiveM resource after build.',\n default: false,\n }),\n server: Flags.string({\n char: 's',\n description: 'Server \"ip:port\" to connect for reloading FiveM resource after build.',\n default: '127.0.0.1:30120',\n required: false,\n }),\n password: Flags.string({\n char: 'p',\n description: 'RCON password for the FiveM server to reload resource after build.',\n required: false,\n }),\n resourceName: Flags.string({\n char: 'n',\n description:\n 'Name of the FiveM resource to reload. If not provided, the name of the folder containing the resource will be used.',\n required: false,\n }),\n };\n\n static override examples = [\n {\n description: 'Build the FiveM resource.',\n command: '<%= config.bin %> <%= command.id %>',\n },\n {\n description: 'Build the FiveM resource in watch mode.',\n command: '<%= config.bin %> <%= command.id %> --watch',\n },\n {\n description: 'Build the FiveM resource in production mode.',\n command: '<%= config.bin %> <%= command.id %> --mode=production',\n },\n {\n description:\n 'Build the FiveM resource and automatically reload it on the server after build.',\n command:\n '<%= config.bin %> <%= command.id %> --auto-reload --password your_rcon_password',\n },\n {\n description:\n 'Build the FiveM resource in watch mode and automatically reload it on the server after each build.',\n command:\n '<%= config.bin %> <%= command.id %> --watch --auto-reload --password your_rcon_password',\n },\n {\n description:\n 'Build the FiveM resource and connect to a specific server for auto-reload.',\n command:\n '<%= config.bin %> <%= command.id %> --auto-reload --server=127.0.0.1:30120 --password your_rcon_password',\n },\n ];\n\n public async run(): Promise<void> {\n const { flags } = await this.parse(FivemBuildCommand);\n\n const { watch, autoReload, password } = flags;\n const mode = (flags.mode ?? (watch ? 'development' : 'production')) as Mode;\n const { host, port } = this._parseServerAddress(flags.server);\n const resourceName = flags.resourceName ?? path.basename(process.cwd());\n\n const config = createFivemRspackConfig({ mode });\n const compiler = rspack(config);\n\n if (autoReload) {\n if (!password) {\n this.fatalError(\n 'RCON password is required for auto-reload. Please provide it using the --password flag.',\n );\n }\n\n await this._enableAutoReload(compiler, resourceName, host, port, password);\n }\n\n if (flags.watch) {\n this.logger.info(`Building FiveM resource in watch mode...\\n`);\n compiler.watch({}, this._compilerCallback.bind(this));\n } else {\n this.logger.info(`Building FiveM resource...\\n`);\n compiler.run(this._compilerCallback.bind(this));\n }\n }\n\n private _parseServerAddress(address: string): ServerAddress {\n const match = /^(?<host>[^:]+):(?<port>\\d+)$/u.exec(address);\n const { host, port } = match?.groups ?? {};\n\n if (!host || !port) {\n throw new Error(\n `Invalid server address format: ${address}. Expected format is \"ip:port\".`,\n );\n }\n\n return { host, port: parseInt(port) };\n }\n\n private _compilerCallback(err: Error | null, stats: Stats | undefined): void {\n if (err) {\n this.logger.error(getErrMsg(err));\n if ('details' in err) this.logger.error(err.details as string);\n if ('stack' in err) this.logger.error(err.stack);\n return;\n }\n\n if (stats) this.logger.log(stats.toString(), '\\n');\n }\n\n private async _connectRcon(host: string, port: number, password: string): Promise<Rcon> {\n return new Promise((resolve, reject) => {\n const rcon = new Rcon(host, port, password, { tcp: false, challenge: false });\n\n rcon.on('auth', () => resolve(rcon));\n rcon.on('error', reject);\n rcon.on('end', () => reject(new Error('RCON connection ended unexpectedly.')));\n\n rcon.connect();\n });\n }\n\n private async _enableAutoReload(\n compiler: Compiler,\n resourceName: string,\n host: string,\n port: number,\n password: string,\n ): Promise<void> {\n const rcon = await this._connectRcon(host, port, password);\n\n rcon.on('response', (res: string) => {\n if (res.includes(\"Couldn't find resource\")) this.fatalError(\"Couldn't find resource\");\n if (res === 'rint Invalid password') this.fatalError('Invalid password');\n });\n\n compiler.hooks.done.tap('FivemAutoReloadPlugin', (stats) => {\n if (stats.hasErrors()) {\n this.logger.warning('Build failed. Skipping FiveM resource reload.\\n');\n return;\n }\n\n this.logger.info(`Reloading FiveM resource \"${resourceName}\"...`);\n try {\n rcon.send(`refresh; ensure ${resourceName}`);\n this.logger.success(`FiveM resource reloaded successfully.\\n`);\n } catch (error) {\n this.logger.error(`Failed to reload FiveM resource: ${getErrMsg(error)}\\n`);\n }\n });\n }\n}\n","import { FivemBuildCommand } from './fivem-build-command';\n\nexport const commands = {\n 'build:fivem': FivemBuildCommand,\n};\n"],"mappings":"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"}
@@ -3,7 +3,32 @@
3
3
  "build:fivem": {
4
4
  "aliases": [],
5
5
  "args": {},
6
- "examples": [],
6
+ "examples": [
7
+ {
8
+ "description": "Build the FiveM resource.",
9
+ "command": "<%= config.bin %> <%= command.id %>"
10
+ },
11
+ {
12
+ "description": "Build the FiveM resource in watch mode.",
13
+ "command": "<%= config.bin %> <%= command.id %> --watch"
14
+ },
15
+ {
16
+ "description": "Build the FiveM resource in production mode.",
17
+ "command": "<%= config.bin %> <%= command.id %> --mode=production"
18
+ },
19
+ {
20
+ "description": "Build the FiveM resource and automatically reload it on the server after build.",
21
+ "command": "<%= config.bin %> <%= command.id %> --auto-reload --password your_rcon_password"
22
+ },
23
+ {
24
+ "description": "Build the FiveM resource in watch mode and automatically reload it on the server after each build.",
25
+ "command": "<%= config.bin %> <%= command.id %> --watch --auto-reload --password your_rcon_password"
26
+ },
27
+ {
28
+ "description": "Build the FiveM resource and connect to a specific server for auto-reload.",
29
+ "command": "<%= config.bin %> <%= command.id %> --auto-reload --server=127.0.0.1:30120 --password your_rcon_password"
30
+ }
31
+ ],
7
32
  "flags": {
8
33
  "watch": {
9
34
  "char": "w",
@@ -71,5 +96,5 @@
71
96
  "summary": "Build the FiveM resource using predefined config."
72
97
  }
73
98
  },
74
- "version": "0.0.2"
99
+ "version": "0.0.4"
75
100
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jpp-toolkit/plugin-build-fivem",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Plugin that add the fivem build command to the jpp cli.",
5
5
  "keywords": [
6
6
  "jpp",
@@ -36,10 +36,10 @@
36
36
  "dependencies": {
37
37
  "@oclif/core": "4.8.0",
38
38
  "@rspack/core": "1.6.7",
39
- "rcon-client": "4.2.5",
40
- "@jpp-toolkit/core": "0.0.14",
41
- "@jpp-toolkit/utils": "0.0.14",
42
- "@jpp-toolkit/rspack-config": "0.0.2"
39
+ "rcon": "1.1.0",
40
+ "@jpp-toolkit/core": "0.0.15",
41
+ "@jpp-toolkit/rspack-config": "0.0.2",
42
+ "@jpp-toolkit/utils": "0.0.14"
43
43
  },
44
44
  "devDependencies": {
45
45
  "oclif": "4.22.54"
@@ -6,7 +6,7 @@ import { getErrMsg } from '@jpp-toolkit/utils';
6
6
  import { Flags } from '@oclif/core';
7
7
  import type { Compiler, Stats } from '@rspack/core';
8
8
  import { rspack } from '@rspack/core';
9
- import { Rcon } from 'rcon-client';
9
+ import Rcon from 'rcon';
10
10
 
11
11
  type Mode = 'development' | 'production';
12
12
  type ServerAddress = { readonly host: string; readonly port: number };
@@ -50,7 +50,38 @@ export class FivemBuildCommand extends Command {
50
50
  }),
51
51
  };
52
52
 
53
- static override examples = [];
53
+ static override examples = [
54
+ {
55
+ description: 'Build the FiveM resource.',
56
+ command: '<%= config.bin %> <%= command.id %>',
57
+ },
58
+ {
59
+ description: 'Build the FiveM resource in watch mode.',
60
+ command: '<%= config.bin %> <%= command.id %> --watch',
61
+ },
62
+ {
63
+ description: 'Build the FiveM resource in production mode.',
64
+ command: '<%= config.bin %> <%= command.id %> --mode=production',
65
+ },
66
+ {
67
+ description:
68
+ 'Build the FiveM resource and automatically reload it on the server after build.',
69
+ command:
70
+ '<%= config.bin %> <%= command.id %> --auto-reload --password your_rcon_password',
71
+ },
72
+ {
73
+ description:
74
+ 'Build the FiveM resource in watch mode and automatically reload it on the server after each build.',
75
+ command:
76
+ '<%= config.bin %> <%= command.id %> --watch --auto-reload --password your_rcon_password',
77
+ },
78
+ {
79
+ description:
80
+ 'Build the FiveM resource and connect to a specific server for auto-reload.',
81
+ command:
82
+ '<%= config.bin %> <%= command.id %> --auto-reload --server=127.0.0.1:30120 --password your_rcon_password',
83
+ },
84
+ ];
54
85
 
55
86
  public async run(): Promise<void> {
56
87
  const { flags } = await this.parse(FivemBuildCommand);
@@ -65,14 +96,12 @@ export class FivemBuildCommand extends Command {
65
96
 
66
97
  if (autoReload) {
67
98
  if (!password) {
68
- this.logger.error(
99
+ this.fatalError(
69
100
  'RCON password is required for auto-reload. Please provide it using the --password flag.',
70
101
  );
71
- this.exit(1);
72
102
  }
73
103
 
74
- const rcon = new Rcon({ host, port, password });
75
- await this._enableAutoReload(compiler, rcon, resourceName);
104
+ await this._enableAutoReload(compiler, resourceName, host, port, password);
76
105
  }
77
106
 
78
107
  if (flags.watch) {
@@ -108,19 +137,33 @@ export class FivemBuildCommand extends Command {
108
137
  if (stats) this.logger.log(stats.toString(), '\n');
109
138
  }
110
139
 
140
+ private async _connectRcon(host: string, port: number, password: string): Promise<Rcon> {
141
+ return new Promise((resolve, reject) => {
142
+ const rcon = new Rcon(host, port, password, { tcp: false, challenge: false });
143
+
144
+ rcon.on('auth', () => resolve(rcon));
145
+ rcon.on('error', reject);
146
+ rcon.on('end', () => reject(new Error('RCON connection ended unexpectedly.')));
147
+
148
+ rcon.connect();
149
+ });
150
+ }
151
+
111
152
  private async _enableAutoReload(
112
153
  compiler: Compiler,
113
- rcon: Rcon,
114
154
  resourceName: string,
155
+ host: string,
156
+ port: number,
157
+ password: string,
115
158
  ): Promise<void> {
116
- try {
117
- await rcon.connect();
118
- } catch (error) {
119
- this.logger.error(`Failed to connect to FiveM server via RCON: ${getErrMsg(error)}`);
120
- this.exit(1);
121
- }
159
+ const rcon = await this._connectRcon(host, port, password);
160
+
161
+ rcon.on('response', (res: string) => {
162
+ if (res.includes("Couldn't find resource")) this.fatalError("Couldn't find resource");
163
+ if (res === 'rint Invalid password') this.fatalError('Invalid password');
164
+ });
122
165
 
123
- compiler.hooks.done.tapPromise('FivemAutoReloadPlugin', async (stats) => {
166
+ compiler.hooks.done.tap('FivemAutoReloadPlugin', (stats) => {
124
167
  if (stats.hasErrors()) {
125
168
  this.logger.warning('Build failed. Skipping FiveM resource reload.\n');
126
169
  return;
@@ -128,7 +171,7 @@ export class FivemBuildCommand extends Command {
128
171
 
129
172
  this.logger.info(`Reloading FiveM resource "${resourceName}"...`);
130
173
  try {
131
- await rcon.send(`refresh; ensure ${resourceName}`);
174
+ rcon.send(`refresh; ensure ${resourceName}`);
132
175
  this.logger.success(`FiveM resource reloaded successfully.\n`);
133
176
  } catch (error) {
134
177
  this.logger.error(`Failed to reload FiveM resource: ${getErrMsg(error)}\n`);