1
- const { app, BrowserWindow, Tray, Menu, ipcMain } = require ( 'electron' ) ;
1
+ const { app, BrowserWindow, Tray, Menu, dialog, ipcMain } = require ( 'electron' ) ;
2
+ require ( 'dotenv' ) . config ( ) ;
2
3
const path = require ( 'path' ) ;
3
4
const fs = require ( 'fs' ) ;
4
5
const Registry = require ( 'winreg' ) ;
6
+ const DiscordRPC = require ( 'discord-rpc' ) ;
5
7
6
8
let mainWindow ;
7
9
let tray = null ;
8
10
11
+ const clientId = process . env . DISCORD_CLIENT_ID ;
12
+ if ( ! clientId ) {
13
+ console . error ( 'DISCORD_CLIENT_ID not found in .env file. Discord RPC will not work.' ) ;
14
+ }
15
+
16
+ const rpc = new DiscordRPC . Client ( { transport : 'ipc' } ) ;
17
+ let rpcReady = false ;
18
+
19
+ if ( clientId ) {
20
+ DiscordRPC . register ( clientId ) ;
21
+
22
+ rpc . on ( 'ready' , ( ) => {
23
+ console . log ( 'Discord RPC is ready' ) ;
24
+ rpcReady = true ;
25
+ updateDiscordActivity ( ) ;
26
+ } ) ;
27
+
28
+ rpc . on ( 'error' , ( err ) => {
29
+ console . error ( 'Discord RPC error:' , err ) ;
30
+ } ) ;
31
+
32
+ rpc . login ( { clientId } ) . catch ( console . error ) ;
33
+ }
34
+
35
+ function updateDiscordActivity ( clientId , theme ) {
36
+ if ( ! rpcReady ) return ;
37
+ rpc . setActivity ( {
38
+ details : `Using ${ theme } theme` ,
39
+ state : `On ${ clientId } Client Page` ,
40
+ startTimestamp : Math . floor ( Date . now ( ) / 1000 ) ,
41
+ largeImageKey : 'twl_main' ,
42
+ largeImageText : '@noxygalaxy' ,
43
+ instance : false ,
44
+ } ) ;
45
+ console . log ( `Discord activity updated for ${ clientId } with ${ theme } theme` ) ;
46
+ }
47
+
48
+ const configPath = path . join ( app . getPath ( 'appData' ) , 'TWLauncher' , 'twlconfig.json' ) ;
49
+ let config = { installPath : path . join ( app . getPath ( 'appData' ) , 'TWLauncher' , 'clients' ) , theme : 'default' } ;
50
+
51
+ if ( fs . existsSync ( configPath ) ) {
52
+ config = JSON . parse ( fs . readFileSync ( configPath , 'utf8' ) ) ;
53
+ }
54
+
55
+ function saveConfig ( ) {
56
+ fs . writeFileSync ( configPath , JSON . stringify ( config , null , 2 ) ) ;
57
+ }
58
+
9
59
function createWindow ( ) {
10
60
mainWindow = new BrowserWindow ( {
11
61
width : 1280 ,
@@ -26,6 +76,10 @@ function createWindow() {
26
76
mainWindow . hide ( ) ;
27
77
} ) ;
28
78
79
+ mainWindow . webContents . on ( 'did-finish-load' , ( ) => {
80
+ mainWindow . webContents . send ( 'apply-theme' , config . theme ) ;
81
+ } ) ;
82
+
29
83
createTray ( ) ;
30
84
}
31
85
@@ -204,6 +258,42 @@ function launchGame(id) {
204
258
mainWindow . webContents . send ( 'launch-game' , id ) ;
205
259
}
206
260
261
+ ipcMain . handle ( 'change-install-path' , async ( ) => {
262
+ const result = await dialog . showOpenDialog ( mainWindow , {
263
+ properties : [ 'openDirectory' ] ,
264
+ title : 'Select Installation Directory'
265
+ } ) ;
266
+ if ( ! result . canceled && result . filePaths . length > 0 ) {
267
+ config . installPath = result . filePaths [ 0 ] ;
268
+ saveConfig ( ) ;
269
+ return config . installPath ;
270
+ }
271
+ return null ;
272
+ } ) ;
273
+
274
+ ipcMain . handle ( 'get-install-path' , ( ) => {
275
+ return config . installPath ;
276
+ } ) ;
277
+
278
+ ipcMain . on ( 'save-settings' , ( event , { installPath, theme } ) => {
279
+ config . installPath = installPath ;
280
+ config . theme = theme ;
281
+ saveConfig ( ) ;
282
+ mainWindow . webContents . send ( 'apply-theme' , theme ) ;
283
+ } ) ;
284
+
285
+ ipcMain . on ( 'select-client' , ( event , clientId ) => {
286
+ mainWindow . webContents . send ( 'client-selected' , clientId ) ;
287
+ } ) ;
288
+
289
+ ipcMain . handle ( 'get-initial-theme' , ( ) => {
290
+ return config . theme ;
291
+ } ) ;
292
+
293
+ ipcMain . on ( 'update-discord-rpc' , ( event , { clientId, theme } ) => {
294
+ updateDiscordActivity ( clientId , theme ) ;
295
+ } ) ;
296
+
207
297
ipcMain . on ( 'minimize-window' , ( ) => {
208
298
mainWindow . minimize ( ) ;
209
299
} ) ;
@@ -215,6 +305,9 @@ ipcMain.on('hide-window', () => {
215
305
content : 'Launcher will work in background, to close it right click on the tray icon' ,
216
306
icon : path . join ( __dirname , 'src' , 'assets' , 'logos' , 'twl.png' ) ,
217
307
} ) ;
308
+ if ( rpcReady ) {
309
+ rpc . destroy ( ) ;
310
+ }
218
311
} ) ;
219
312
220
313
ipcMain . on ( 'launch-game' , async ( ) => {
@@ -223,8 +316,7 @@ ipcMain.on('launch-game', async () => {
223
316
} ) ;
224
317
225
318
app . whenReady ( ) . then ( ( ) => {
226
- const appDataPath = app . getPath ( 'appData' ) ;
227
- const clientsPath = path . join ( appDataPath , 'TWLauncher' , 'clients' ) ;
319
+ const clientsPath = config . installPath ;
228
320
229
321
if ( ! fs . existsSync ( clientsPath ) ) {
230
322
fs . mkdirSync ( clientsPath , { recursive : true } ) ;
0 commit comments