11var _ = require ( 'lodash' )
22var events = require ( 'events' )
33var fs = require ( 'fs' )
4+ var fsExtra = require ( 'fs.extra' )
45var Gamedig = require ( 'gamedig' )
6+ var glob = require ( 'glob' )
7+ var path = require ( 'path' )
58var slugify = require ( 'slugify' )
69
710var ArmaServer = require ( 'arma-server' )
@@ -134,6 +137,104 @@ Server.prototype.start = function () {
134137 return this
135138 }
136139
140+ var self = this
141+
142+ const requiredFileExtensions = [ '.dll' , '.exe' , '.so' , '.txt' ]
143+ const serverFolders = [
144+ 'addons' ,
145+ 'argo' ,
146+ 'battleye' ,
147+ 'contact' ,
148+ 'curator' ,
149+ 'dll' ,
150+ 'dta' ,
151+ 'enoch' ,
152+ 'expansion' ,
153+ 'gm' ,
154+ 'heli' ,
155+ 'jets' ,
156+ 'kart' ,
157+ 'mark' ,
158+ 'mpmissions' ,
159+ 'orange' ,
160+ 'tacops' ,
161+ 'tank'
162+ ]
163+ const symlinkFolders = serverFolders . concat ( self . mods ) . concat ( config . serverMods )
164+
165+ return fs . promises . mkdtemp ( path . join ( self . config . path , 'arma-server-' ) )
166+ . then ( ( serverFolder ) => {
167+ self . virtualServerFolder = serverFolder
168+ console . log ( 'Created virtual server folder:' , serverFolder )
169+
170+ return fs . promises . readdir ( self . config . path )
171+ . then ( ( files ) => {
172+ // Copy needed files, file symlinks on Windows are sketchy
173+ const serverFiles = files . filter ( ( file ) => requiredFileExtensions . indexOf ( path . extname ( file ) ) >= 0 || path . basename ( file ) === 'arma3server' )
174+ return Promise . all ( serverFiles . map ( ( file ) => {
175+ return fs . promises . copyFile ( path . join ( self . config . path , file ) , path . join ( serverFolder , file ) )
176+ } ) )
177+ } )
178+ . then ( ( ) => {
179+ // Create virtual folders from default Arma and mods
180+ return Promise . all ( symlinkFolders . map ( ( symlink ) => {
181+ return fs . promises . access ( path . join ( self . config . path , symlink ) )
182+ . then ( ( ) => {
183+ return fs . promises . symlink ( path . join ( self . config . path , symlink ) , path . join ( serverFolder , symlink ) , 'junction' )
184+ } )
185+ . catch ( ( err ) => {
186+ console . error ( 'Could create symlink for' , symlink , 'due to' , err )
187+ } )
188+ } ) )
189+ } )
190+ . then ( ( ) => {
191+ // Copy needed keys, file symlinks on Windows are sketchy
192+ const keysFolder = path . join ( serverFolder , 'keys' )
193+ return fs . promises . mkdir ( keysFolder , { recursive : true } )
194+ . then ( ( ) => {
195+ const defaultKeysPath = path . join ( self . config . path , 'keys' )
196+ const defaultKeysPromise = fs . promises . readdir ( defaultKeysPath )
197+ . then ( ( files ) => files . filter ( ( file ) => path . extname ( file ) === '.bikey' ) )
198+ . then ( ( files ) => files . map ( ( file ) => path . join ( defaultKeysPath , file ) ) )
199+
200+ const modKeysPromise = Promise . all ( self . mods . map ( mod => {
201+ return new Promise ( ( resolve , reject ) => {
202+ const modPath = path . join ( this . config . path , mod )
203+ glob ( `${ modPath } /**/*.bikey` , function ( err , files ) {
204+ if ( err ) {
205+ return reject ( err )
206+ }
207+
208+ return resolve ( files )
209+ } )
210+ } )
211+ } ) ) . then ( ( modsFiles ) => modsFiles . flat ( ) )
212+
213+ return Promise . all ( [ defaultKeysPromise , modKeysPromise ] . map ( ( promise ) => {
214+ return promise . then ( ( keyFiles ) => {
215+ return Promise . all ( keyFiles . map ( ( keyFile ) => {
216+ return fs . promises . copyFile ( keyFile , path . join ( keysFolder , path . basename ( keyFile ) ) )
217+ } ) )
218+ } )
219+ } ) ) . catch ( ( err ) => {
220+ console . error ( 'Error copying keys:' , err )
221+ } )
222+ } )
223+ } )
224+ . then ( ( ) => {
225+ self . realStart ( serverFolder )
226+ } )
227+ . catch ( ( err ) => {
228+ console . error ( 'Error creating virtual server folder:' , err )
229+ } )
230+ } )
231+ }
232+
233+ Server . prototype . realStart = function ( path ) {
234+ if ( this . instance ) {
235+ return this
236+ }
237+
137238 var parameters = this . getParameters ( )
138239 var server = new ArmaServer . Server ( {
139240 additionalConfigurationOptions : this . getAdditionalConfigurationOptions ( ) ,
@@ -154,7 +255,7 @@ Server.prototype.start = function () {
154255 parameters : parameters ,
155256 password : this . password ,
156257 passwordAdmin : this . admin_password ,
157- path : this . config . path ,
258+ path : path ,
158259 persistent : this . persistent ? 1 : 0 ,
159260 platform : this . config . type ,
160261 players : this . max_players ,
@@ -196,8 +297,18 @@ Server.prototype.start = function () {
196297 self . instance = null
197298
198299 self . stopHeadlessClients ( )
199-
200- self . emit ( 'state' )
300+ . then ( ( ) => {
301+ if ( self . virtualServerFolder ) {
302+ fsExtra . rmrf ( self . virtualServerFolder , function ( err ) {
303+ if ( err ) {
304+ console . log ( 'Error removing virtual server folder' , err )
305+ }
306+ } )
307+ self . virtualServerFolder = null
308+ }
309+
310+ self . emit ( 'state' )
311+ } )
201312 } )
202313
203314 instance . on ( 'error' , function ( err ) {
@@ -210,14 +321,14 @@ Server.prototype.start = function () {
210321 self . queryStatus ( )
211322 } , queryInterval )
212323
213- this . startHeadlessClients ( )
324+ this . startHeadlessClients ( path )
214325
215326 this . emit ( 'state' )
216327
217328 return this
218329}
219330
220- Server . prototype . startHeadlessClients = function ( ) {
331+ Server . prototype . startHeadlessClients = function ( path ) {
221332 var parameters = this . getParameters ( )
222333 var self = this
223334 var headlessClientInstances = _ . times ( this . number_of_headless_clients , function ( i ) {
@@ -228,7 +339,7 @@ Server.prototype.startHeadlessClients = function () {
228339 mods : self . mods ,
229340 parameters : parameters ,
230341 password : self . password ,
231- path : self . config . path ,
342+ path : path ,
232343 platform : self . config . type ,
233344 port : self . port
234345 } )
@@ -293,9 +404,9 @@ Server.prototype.stop = function (cb) {
293404}
294405
295406Server . prototype . stopHeadlessClients = function ( ) {
296- this . headlessClientInstances . map ( function ( headlessClientInstance ) {
297- headlessClientInstance . kill ( )
298- } )
407+ return Promise . all ( this . headlessClientInstances . map ( function ( headlessClientInstance ) {
408+ return headlessClientInstance . kill ( )
409+ } ) )
299410}
300411
301412Server . prototype . toJSON = function ( ) {
0 commit comments