@@ -3,11 +3,11 @@ const path = require('path');
3
3
const fs = require ( 'fs' ) ;
4
4
const Registry = require ( 'winreg' ) ;
5
5
6
- let wnxKjd ;
7
- let tryxNoxy = null ;
6
+ let mainWindow ;
7
+ let tray = null ;
8
8
9
- function crtWndFksj ( ) {
10
- wnxKjd = new BrowserWindow ( {
9
+ function createWindow ( ) {
10
+ mainWindow = new BrowserWindow ( {
11
11
width : 1280 ,
12
12
height : 720 ,
13
13
webPreferences : {
@@ -20,229 +20,229 @@ function crtWndFksj() {
20
20
icon : path . join ( __dirname , 'src' , 'assets' , 'logos' , 'twl.png' ) ,
21
21
} ) ;
22
22
23
- wnxKjd . loadFile ( 'src/index.html' ) ;
24
- wnxKjd . on ( 'close' , ( evntPqr ) => {
25
- evntPqr . preventDefault ( ) ;
26
- wnxKjd . hide ( ) ;
23
+ mainWindow . loadFile ( 'src/index.html' ) ;
24
+ mainWindow . on ( 'close' , ( event ) => {
25
+ event . preventDefault ( ) ;
26
+ mainWindow . hide ( ) ;
27
27
} ) ;
28
28
29
- crtTryGhl ( ) ;
29
+ createTray ( ) ;
30
30
}
31
31
32
- function gtStmPthJkl ( ) {
33
- return new Promise ( ( rslvMno ) => {
34
- const rgKyAbc = new Registry ( { hive : Registry . HKCU , key : '\\Software\\Valve\\Steam' } ) ;
35
- rgKyAbc . get ( 'SteamPath' , ( errXyz , itmDef ) => {
36
- if ( errXyz ) {
37
- console . error ( 'Error getting Steam path:' , errXyz ) ;
38
- rslvMno ( null ) ;
32
+ function getSteamPath ( ) {
33
+ return new Promise ( ( resolve ) => {
34
+ const registryKey = new Registry ( { hive : Registry . HKCU , key : '\\Software\\Valve\\Steam' } ) ;
35
+ registryKey . get ( 'SteamPath' , ( error , item ) => {
36
+ if ( error ) {
37
+ console . error ( 'Error getting Steam path:' , error ) ;
38
+ resolve ( null ) ;
39
39
} else {
40
- rslvMno ( itmDef ? itmDef . value : null ) ;
40
+ resolve ( item ? item . value : null ) ;
41
41
}
42
42
} ) ;
43
43
} ) ;
44
44
}
45
45
46
- function prsLbrFldsQwe ( stmPthRty ) {
46
+ function parseLibraryFolders ( steamPath ) {
47
47
try {
48
- const vdfPthUio = path . join ( stmPthRty , 'steamapps' , 'libraryfolders.vdf' ) ;
49
- if ( ! fs . existsSync ( vdfPthUio ) ) {
50
- console . log ( 'libraryfolders.vdf not found at:' , vdfPthUio ) ;
48
+ const vdfPath = path . join ( steamPath , 'steamapps' , 'libraryfolders.vdf' ) ;
49
+ if ( ! fs . existsSync ( vdfPath ) ) {
50
+ console . log ( 'libraryfolders.vdf not found at:' , vdfPath ) ;
51
51
return { } ;
52
52
}
53
53
54
- const cntntPas = fs . readFileSync ( vdfPthUio , 'utf8' ) ;
55
- const lbrFldsDfg = { } ;
56
- let crrntFldrHjk = null ;
57
- let inAppsLmn = false ;
58
-
59
- cntntPas . split ( '\n' ) . forEach ( lnOpq => {
60
- const trmmdRst = lnOpq . trim ( ) ;
61
- const fldrMtchUvw = trmmdRst . match ( / ^ " ( \d + ) " $ / ) ;
62
- if ( fldrMtchUvw && ! inAppsLmn ) {
63
- crrntFldrHjk = fldrMtchUvw [ 1 ] ;
64
- lbrFldsDfg [ crrntFldrHjk ] = { path : '' , apps : { } } ;
65
- } else if ( crrntFldrHjk && trmmdRst . startsWith ( '"path"' ) ) {
66
- const pthMtchXyz = trmmdRst . match ( / " p a t h " \s + " ( .+ ) " / ) ;
67
- if ( pthMtchXyz ) lbrFldsDfg [ crrntFldrHjk ] . path = pthMtchXyz [ 1 ] . replace ( / \\ \\ / g, '\\' ) ;
68
- } else if ( trmmdRst === '"apps"' ) {
69
- inAppsLmn = true ;
70
- } else if ( trmmdRst === '}' && inAppsLmn ) {
71
- inAppsLmn = false ;
72
- } else if ( inAppsLmn && trmmdRst . match ( / ^ " ( \d + ) " / ) ) {
73
- const appMtchBcd = trmmdRst . match ( / " ( \d + ) " \s + " ( \d + ) " / ) ;
74
- if ( appMtchBcd ) lbrFldsDfg [ crrntFldrHjk ] . apps [ appMtchBcd [ 1 ] ] = appMtchBcd [ 2 ] ;
54
+ const content = fs . readFileSync ( vdfPath , 'utf8' ) ;
55
+ const libraryFolders = { } ;
56
+ let currentFolder = null ;
57
+ let inAppsSection = false ;
58
+
59
+ content . split ( '\n' ) . forEach ( line => {
60
+ const trimmedLine = line . trim ( ) ;
61
+ const folderMatch = trimmedLine . match ( / ^ " ( \d + ) " $ / ) ;
62
+ if ( folderMatch && ! inAppsSection ) {
63
+ currentFolder = folderMatch [ 1 ] ;
64
+ libraryFolders [ currentFolder ] = { path : '' , apps : { } } ;
65
+ } else if ( currentFolder && trimmedLine . startsWith ( '"path"' ) ) {
66
+ const pathMatch = trimmedLine . match ( / " p a t h " \s + " ( .+ ) " / ) ;
67
+ if ( pathMatch ) libraryFolders [ currentFolder ] . path = pathMatch [ 1 ] . replace ( / \\ \\ / g, '\\' ) ;
68
+ } else if ( trimmedLine === '"apps"' ) {
69
+ inAppsSection = true ;
70
+ } else if ( trimmedLine === '}' && inAppsSection ) {
71
+ inAppsSection = false ;
72
+ } else if ( inAppsSection && trimmedLine . match ( / ^ " ( \d + ) " / ) ) {
73
+ const appMatch = trimmedLine . match ( / " ( \d + ) " \s + " ( \d + ) " / ) ;
74
+ if ( appMatch ) libraryFolders [ currentFolder ] . apps [ appMatch [ 1 ] ] = appMatch [ 2 ] ;
75
75
}
76
76
} ) ;
77
- return lbrFldsDfg ;
78
- } catch ( errEfg ) {
79
- console . error ( 'Error parsing library folders:' , errEfg ) ;
77
+ return libraryFolders ;
78
+ } catch ( error ) {
79
+ console . error ( 'Error parsing library folders:' , error ) ;
80
80
return { } ;
81
81
}
82
82
}
83
83
84
- async function isStmGmInstldHij ( stmPthJkl , appIdMno , gmFldrPqr ) {
84
+ async function isSteamGameInstalled ( steamPath , appId , gameFolder ) {
85
85
try {
86
- const drctPthStu = path . join ( stmPthJkl , 'steamapps' , 'common' , gmFldrPqr ) ;
87
- if ( fs . existsSync ( drctPthStu ) ) return true ;
88
-
89
- const lbrFldsVwx = prsLbrFldsQwe ( stmPthJkl ) ;
90
- for ( const fldrYza in lbrFldsVwx ) {
91
- if ( lbrFldsVwx [ fldrYza ] . apps [ appIdMno ] ) {
92
- const gmPthBcd = path . join ( lbrFldsVwx [ fldrYza ] . path , 'steamapps' , 'common' , gmFldrPqr ) ;
93
- if ( fs . existsSync ( gmPthBcd ) ) return true ;
86
+ const directPath = path . join ( steamPath , 'steamapps' , 'common' , gameFolder ) ;
87
+ if ( fs . existsSync ( directPath ) ) return true ;
88
+
89
+ const libraryFolders = parseLibraryFolders ( steamPath ) ;
90
+ for ( const folder in libraryFolders ) {
91
+ if ( libraryFolders [ folder ] . apps [ appId ] ) {
92
+ const gamePath = path . join ( libraryFolders [ folder ] . path , 'steamapps' , 'common' , gameFolder ) ;
93
+ if ( fs . existsSync ( gamePath ) ) return true ;
94
94
}
95
95
}
96
96
return false ;
97
- } catch ( errDef ) {
98
- console . error ( 'Error checking Steam game installation:' , errDef ) ;
97
+ } catch ( error ) {
98
+ console . error ( 'Error checking Steam game installation:' , error ) ;
99
99
return false ;
100
100
}
101
101
}
102
102
103
- async function gtGmPthGhi ( gmIdJkl ) {
104
- const appDtaPthMno = app . getPath ( 'appData' ) ;
105
- const gmsPqr = {
103
+ async function getGamePath ( gameId ) {
104
+ const appDataPath = app . getPath ( 'appData' ) ;
105
+ const games = {
106
106
'tw' : { steamAppId : '380840' , steamGameFolder : 'Teeworlds' } ,
107
107
'ddnet' : { steamAppId : '412220' , steamGameFolder : 'DDraceNetwork' } ,
108
108
'tclient' : { clientName : 'TClient' } ,
109
109
'cactus' : { clientName : 'Cactus' }
110
110
} ;
111
111
112
- const gmDtaStu = gmsPqr [ gmIdJkl ] ;
113
- if ( ! gmDtaStu ) return false ;
112
+ const gameData = games [ gameId ] ;
113
+ if ( ! gameData ) return false ;
114
114
115
- if ( gmDtaStu . steamAppId ) {
116
- const stmPthVwx = await gtStmPthJkl ( ) ;
117
- if ( ! stmPthVwx ) return false ;
118
- return await isStmGmInstldHij ( stmPthVwx , gmDtaStu . steamAppId , gmDtaStu . steamGameFolder ) ;
119
- } else if ( gmDtaStu . clientName ) {
120
- const clntPthYza = path . join ( appDtaPthMno , 'TWLauncher' , 'clients' , gmDtaStu . clientName ) ;
121
- return fs . existsSync ( clntPthYza ) ;
115
+ if ( gameData . steamAppId ) {
116
+ const steamPath = await getSteamPath ( ) ;
117
+ if ( ! steamPath ) return false ;
118
+ return await isSteamGameInstalled ( steamPath , gameData . steamAppId , gameData . steamGameFolder ) ;
119
+ } else if ( gameData . clientName ) {
120
+ const clientPath = path . join ( appDataPath , 'TWLauncher' , 'clients' , gameData . clientName ) ;
121
+ return fs . existsSync ( clientPath ) ;
122
122
}
123
123
return false ;
124
124
}
125
125
126
- async function bldTryMnuAbc ( ) {
126
+ async function buildTrayMenu ( ) {
127
127
try {
128
- const isTwInstldDef = await gtGmPthGhi ( 'tw' ) ;
129
- const isDdnetInstldGhi = await gtGmPthGhi ( 'ddnet' ) ;
130
- const isTclntInstldJkl = await gtGmPthGhi ( 'tclient' ) ;
131
- const isCctsInstldMno = await gtGmPthGhi ( 'cactus' ) ;
128
+ const isTeeworldsInstalled = await getGamePath ( 'tw' ) ;
129
+ const isDdnetInstalled = await getGamePath ( 'ddnet' ) ;
130
+ const isTclientInstalled = await getGamePath ( 'tclient' ) ;
131
+ const isCactusInstalled = await getGamePath ( 'cactus' ) ;
132
132
133
133
console . log ( 'Building tray menu with status:' , {
134
- Teeworlds : isTwInstldDef ,
135
- DDraceNetwork : isDdnetInstldGhi ,
136
- TClient : isTclntInstldJkl ,
137
- Cactus : isCctsInstldMno
134
+ Teeworlds : isTeeworldsInstalled ,
135
+ DDraceNetwork : isDdnetInstalled ,
136
+ TClient : isTclientInstalled ,
137
+ Cactus : isCactusInstalled
138
138
} ) ;
139
139
140
- const lnchSubmnuPqr = Menu . buildFromTemplate ( [
140
+ const launchSubmenu = Menu . buildFromTemplate ( [
141
141
{
142
142
label : 'Teeworlds' ,
143
143
icon : path . join ( __dirname , 'src' , 'assets' , 'tray' , 'tw.png' ) ,
144
- click : ( ) => lnchGmStu ( 'tw' ) ,
145
- enabled : isTwInstldDef
144
+ click : ( ) => launchGame ( 'tw' ) ,
145
+ enabled : isTeeworldsInstalled
146
146
} ,
147
147
{
148
148
label : 'DDraceNetwork' ,
149
149
icon : path . join ( __dirname , 'src' , 'assets' , 'tray' , 'ddnet.png' ) ,
150
- click : ( ) => lnchGmStu ( 'ddnet' ) ,
151
- enabled : isDdnetInstldGhi
150
+ click : ( ) => launchGame ( 'ddnet' ) ,
151
+ enabled : isDdnetInstalled
152
152
} ,
153
153
{
154
154
label : 'TClient' ,
155
155
icon : path . join ( __dirname , 'src' , 'assets' , 'tray' , 'tclient.png' ) ,
156
- click : ( ) => lnchGmStu ( 'tclient' ) ,
157
- enabled : isTclntInstldJkl
156
+ click : ( ) => launchGame ( 'tclient' ) ,
157
+ enabled : isTclientInstalled
158
158
} ,
159
159
{
160
160
label : 'Cactus' ,
161
161
icon : path . join ( __dirname , 'src' , 'assets' , 'tray' , 'cactus.png' ) ,
162
- click : ( ) => lnchGmStu ( 'cactus' ) ,
163
- enabled : isCctsInstldMno
162
+ click : ( ) => launchGame ( 'cactus' ) ,
163
+ enabled : isCactusInstalled
164
164
}
165
165
] ) ;
166
166
167
167
return Menu . buildFromTemplate ( [
168
- { label : 'Show App' , click : ( ) => wnxKjd . show ( ) } ,
169
- { label : 'Launch' , submenu : lnchSubmnuPqr } ,
168
+ { label : 'Show App' , click : ( ) => mainWindow . show ( ) } ,
169
+ { label : 'Launch' , submenu : launchSubmenu } ,
170
170
{ label : 'Close App' , click : ( ) => {
171
- wnxKjd . destroy ( ) ;
171
+ mainWindow . destroy ( ) ;
172
172
app . quit ( ) ;
173
173
} } ,
174
174
] ) ;
175
- } catch ( errVwx ) {
176
- console . error ( 'Error building tray menu:' , errVwx ) ;
175
+ } catch ( error ) {
176
+ console . error ( 'Error building tray menu:' , error ) ;
177
177
return Menu . buildFromTemplate ( [
178
- { label : 'Show App' , click : ( ) => wnxKjd . show ( ) } ,
178
+ { label : 'Show App' , click : ( ) => mainWindow . show ( ) } ,
179
179
{ label : 'Close App' , click : ( ) => {
180
- wnxKjd . destroy ( ) ;
180
+ mainWindow . destroy ( ) ;
181
181
app . quit ( ) ;
182
182
} }
183
183
] ) ;
184
184
}
185
185
}
186
186
187
- function crtTryGhl ( ) {
188
- tryxNoxy = new Tray ( path . join ( __dirname , 'src' , 'assets' , 'logos' , 'twl.png' ) ) ;
189
- tryxNoxy . setToolTip ( 'TWLauncher by noxygalaxy' ) ;
187
+ function createTray ( ) {
188
+ tray = new Tray ( path . join ( __dirname , 'src' , 'assets' , 'logos' , 'twl.png' ) ) ;
189
+ tray . setToolTip ( 'TWLauncher by noxygalaxy' ) ;
190
190
191
- tryxNoxy . on ( 'right-click' , async ( ) => {
191
+ tray . on ( 'right-click' , async ( ) => {
192
192
console . log ( 'Tray right-clicked' ) ;
193
- const mnuYza = await bldTryMnuAbc ( ) ;
194
- tryxNoxy . popUpContextMenu ( mnuYza ) ;
193
+ const menu = await buildTrayMenu ( ) ;
194
+ tray . popUpContextMenu ( menu ) ;
195
195
} ) ;
196
196
197
- bldTryMnuAbc ( ) . then ( mnuBcd => {
198
- tryxNoxy . setContextMenu ( mnuBcd ) ;
197
+ buildTrayMenu ( ) . then ( menu => {
198
+ tray . setContextMenu ( menu ) ;
199
199
} ) ;
200
200
}
201
201
202
- function lnchGmStu ( idEfg ) {
203
- console . log ( `Launching game: ${ idEfg } ` ) ;
204
- wnxKjd . webContents . send ( 'launch-game' , idEfg ) ;
202
+ function launchGame ( id ) {
203
+ console . log ( `Launching game: ${ id } ` ) ;
204
+ mainWindow . webContents . send ( 'launch-game' , id ) ;
205
205
}
206
206
207
207
ipcMain . on ( 'minimize-window' , ( ) => {
208
- wnxKjd . minimize ( ) ;
208
+ mainWindow . minimize ( ) ;
209
209
} ) ;
210
210
211
211
ipcMain . on ( 'hide-window' , ( ) => {
212
- wnxKjd . hide ( ) ;
213
- tryxNoxy . displayBalloon ( {
214
- title :'TWLauncher' ,
215
- content :'Launcher will work in background, to close it right click on the tray icon' ,
212
+ mainWindow . hide ( ) ;
213
+ tray . displayBalloon ( {
214
+ title : 'TWLauncher' ,
215
+ content : 'Launcher will work in background, to close it right click on the tray icon' ,
216
216
icon : path . join ( __dirname , 'src' , 'assets' , 'logos' , 'twl.png' ) ,
217
217
} ) ;
218
218
} ) ;
219
219
220
220
ipcMain . on ( 'launch-game' , async ( ) => {
221
- const mnuHij = await bldTryMnuAbc ( ) ;
222
- tryxNoxy . setContextMenu ( mnuHij ) ;
221
+ const menu = await buildTrayMenu ( ) ;
222
+ tray . setContextMenu ( menu ) ;
223
223
} ) ;
224
224
225
225
app . whenReady ( ) . then ( ( ) => {
226
- const appDtaPthJkl = app . getPath ( 'appData' ) ;
227
- const clntsPthMno = path . join ( appDtaPthJkl , 'TWLauncher' , 'clients' ) ;
226
+ const appDataPath = app . getPath ( 'appData' ) ;
227
+ const clientsPath = path . join ( appDataPath , 'TWLauncher' , 'clients' ) ;
228
228
229
- if ( ! fs . existsSync ( clntsPthMno ) ) {
230
- fs . mkdirSync ( clntsPthMno , { recursive : true } ) ;
229
+ if ( ! fs . existsSync ( clientsPath ) ) {
230
+ fs . mkdirSync ( clientsPath , { recursive : true } ) ;
231
231
}
232
232
233
- crtWndFksj ( ) ;
233
+ createWindow ( ) ;
234
234
235
235
app . on ( 'activate' , ( ) => {
236
- if ( BrowserWindow . getAllWindows ( ) . length === 0 ) crtWndFksj ( ) ;
237
- else wnxKjd . show ( ) ;
236
+ if ( BrowserWindow . getAllWindows ( ) . length === 0 ) createWindow ( ) ;
237
+ else mainWindow . show ( ) ;
238
238
} ) ;
239
239
} ) ;
240
240
241
- app . on ( 'window-all-closed' , ( ePqr ) => {
242
- ePqr . preventDefault ( ) ;
243
- tryxNoxy . displayBalloon ( {
244
- title :'TWLauncher' ,
245
- content :'Goodbye! <3' ,
241
+ app . on ( 'window-all-closed' , ( event ) => {
242
+ event . preventDefault ( ) ;
243
+ tray . displayBalloon ( {
244
+ title : 'TWLauncher' ,
245
+ content : 'Goodbye! <3' ,
246
246
icon : path . join ( __dirname , 'src' , 'assets' , 'logos' , 'twl.png' ) ,
247
247
} ) ;
248
- } ) ;
248
+ } ) ;
0 commit comments