Skip to content

Commit 5263310

Browse files
committed
Arma Reforger support
1 parent b851139 commit 5263310

32 files changed

+795
-23
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ A simple to use web admin panel for Arma servers.
3535
- cwa (does not support linux)
3636
- ofp
3737
- ofpresistance
38+
- reforger
3839

3940
## Config
4041

Diff for: app.js

+10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
var express = require('express')
22
var bodyParser = require('body-parser')
3+
var fs = require('fs.extra')
34
var morgan = require('morgan')
45
var path = require('path')
56
var serveStatic = require('serve-static')
@@ -15,6 +16,15 @@ var Mods = require('./lib/mods')
1516
var Logs = require('./lib/logs')
1617
var Settings = require('./lib/settings')
1718

19+
if (config.game === 'reforger') {
20+
Logs = require('./lib/reforger/logs')
21+
Manager = require('./lib/reforger/manager')
22+
Missions = require('./lib/reforger/missions')
23+
Mods = require('./lib/reforger/mods')
24+
25+
fs.mkdirp(config.reforger.profiles) // Needs to be created in advance or game will store profiles elsewhere
26+
}
27+
1828
var app = express()
1929
var server = require('http').Server(app)
2030
var io = require('socket.io')(server)

Diff for: config.docker.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
1-
for (var environmentVariable of ['GAME_TYPE', 'GAME_PATH']) {
1+
['GAME_TYPE', 'GAME_PATH'].forEach(function (environmentVariable) {
22
if (!process.env[environmentVariable]) {
33
console.log('Missing required environment variable "' + environmentVariable + '"')
44
process.exit(1)
55
}
6+
})
7+
8+
if (process.env.GAME_TYPE === 'reforger') {
9+
['REFORGER_CONFIGS', 'REFORGER_PROFILES', 'REFORGER_REGION', 'REFORGER_WORKSHOP'].forEach(function (environmentVariable) {
10+
if (!process.env[environmentVariable]) {
11+
console.log('Missing required environment variable "' + environmentVariable + '"')
12+
process.exit(1)
13+
}
14+
})
615
}
716

817
module.exports = {
@@ -19,6 +28,12 @@ module.exports = {
1928
username: process.env.AUTH_USERNAME,
2029
password: process.env.AUTH_PROCESS
2130
},
31+
reforger: {
32+
configs: process.env.REFORGER_CONFIGS,
33+
profiles: process.env.REFORGER_PROFILES,
34+
region: process.env.REFORGER_REGION,
35+
workshop: process.env.REFORGER_WORKSHOP
36+
},
2237
prefix: process.env.SERVER_PREFIX,
2338
suffix: process.env.SERVER_SUFFIX,
2439
logFormat: process.env.LOG_FORMAT || 'dev'

Diff for: config.js.example

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module.exports = {
2-
game: 'arma3', // arma3, arma2oa, arma2, arma1, cwa, ofpresistance, ofp
2+
game: 'arma3', // arma3, arma2oa, arma2, arma1, cwa, ofpresistance, ofp, reforger
33
path: 'path-to-arma3-directory',
44
port: 3000,
55
host: '0.0.0.0', // Can be either an IP or a Hostname
@@ -9,6 +9,12 @@ module.exports = {
99
'-noSound',
1010
'-world=empty'
1111
],
12+
reforger: {
13+
configs: 'path-to-configs-folder', // Folder where server config files will be stored
14+
profiles: 'path-to-profiles-folder', // Folder where logs and persistence data will be stored. Each server will create a subfolder.
15+
region: 'EU', // Region in which servers will be hosted, https://community.bistudio.com/wiki/Arma_Reforger:Server_Hosting#region
16+
workshop: 'path-to-workshop-folder' // Folder where workshop mods will be stored
17+
},
1218
serverMods: [ // Mods used exclusively by server and not shared with clients
1319
'@mod1',
1420
'@mod2',

Diff for: lib/mods/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ Mods.prototype.resolveModData = function (modPath, cb) {
7070
}
7171

7272
cb(null, {
73+
id: modPath,
7374
name: modPath,
7475
size: results.folderSize,
7576
formattedSize: filesize(results.folderSize),

Diff for: lib/reforger/logs.js

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
var async = require('async')
2+
var filesize = require('filesize')
3+
var fs = require('fs.extra')
4+
var glob = require('glob')
5+
var path = require('path')
6+
7+
var Logs = function (config) {
8+
this.config = config
9+
}
10+
11+
Logs.prototype.delete = function (filename, callback) {
12+
callback = callback || function () {}
13+
14+
this.getLogFile(filename, function (err, logFile) {
15+
if (err) {
16+
return callback(err)
17+
} else {
18+
if (logFile && logFile.path) {
19+
fs.unlink(logFile.path, callback)
20+
} else {
21+
return callback(new Error('File not found'))
22+
}
23+
}
24+
})
25+
}
26+
27+
Logs.prototype.logsPath = function () {
28+
return this.config.reforger.profiles
29+
}
30+
31+
Logs.prototype.logFiles = function (callback) {
32+
var directory = this.logsPath()
33+
34+
if (directory === null) {
35+
return callback(null, [])
36+
}
37+
38+
glob('**/*.log', { cwd: directory }, function (err, files) {
39+
if (err) {
40+
callback(err)
41+
return
42+
}
43+
44+
files = files.map(function (file) {
45+
return {
46+
name: file,
47+
path: path.join(directory, file)
48+
}
49+
})
50+
51+
async.filter(files, function (file, cb) {
52+
fs.stat(file.path, function (err, stat) {
53+
if (err) {
54+
return cb(err)
55+
}
56+
57+
file.created = stat.birthtime.toISOString()
58+
file.modified = stat.mtime.toISOString()
59+
file.formattedSize = filesize(stat.size)
60+
file.size = stat.size
61+
cb(null, stat.isFile())
62+
})
63+
}, function (err, files) {
64+
if (err) {
65+
return callback(err)
66+
}
67+
68+
files.sort(function (a, b) {
69+
return b.created.localeCompare(a.created) // Descending order
70+
})
71+
72+
callback(null, files)
73+
})
74+
})
75+
}
76+
77+
Logs.prototype.getLogFile = function (filename, callback) {
78+
this.logFiles(function (err, files) {
79+
if (err) {
80+
callback(err)
81+
} else {
82+
var validLogs = files.filter(function (file) {
83+
return file.name === filename
84+
})
85+
86+
if (validLogs.length > 0) {
87+
callback(null, validLogs[0])
88+
} else {
89+
callback(null, null)
90+
}
91+
}
92+
})
93+
}
94+
95+
Logs.prototype.readLogFile = function (filename, callback) {
96+
fs.readFile(filename, callback)
97+
}
98+
99+
module.exports = Logs

Diff for: lib/reforger/manager.js

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
var events = require('events')
2+
var fs = require('fs')
3+
4+
var Server = require('./server')
5+
6+
var filePath = 'servers.json'
7+
8+
var Manager = function (config, logs) {
9+
this.config = config
10+
this.logs = logs
11+
this.serversArr = []
12+
this.serversHash = {}
13+
}
14+
15+
Manager.prototype = new events.EventEmitter()
16+
17+
Manager.prototype.addServer = function (options) {
18+
var server = this._addServer(options)
19+
this.save()
20+
return server
21+
}
22+
23+
Manager.prototype.removeServer = function (id) {
24+
var server = this.serversHash[id]
25+
26+
if (!server) {
27+
return {}
28+
}
29+
30+
var index = this.serversArr.indexOf(server)
31+
if (index > -1) {
32+
this.serversArr.splice(index, 1)
33+
}
34+
this.save()
35+
36+
if (server.pid) {
37+
server.stop()
38+
}
39+
40+
return server
41+
}
42+
43+
Manager.prototype._addServer = function (data) {
44+
var server = new Server(this.config, this.logs, data)
45+
this.serversArr.push(server)
46+
this.serversArr.sort(function (a, b) {
47+
return a.title.localeCompare(b.title)
48+
})
49+
this.serversHash[server.id] = server
50+
51+
var self = this
52+
var save = function () {
53+
self.save()
54+
}
55+
var statusChanged = function () {
56+
self.emit('servers')
57+
}
58+
server.on('save', save)
59+
server.on('state', statusChanged)
60+
61+
return server
62+
}
63+
64+
Manager.prototype.getServer = function (id) {
65+
return this.serversHash[id]
66+
}
67+
68+
Manager.prototype.getServers = function () {
69+
return this.serversArr
70+
}
71+
72+
Manager.prototype.load = function () {
73+
var self = this
74+
75+
fs.readFile(filePath, function (err, data) {
76+
if (err) {
77+
console.log('Could not load any existing servers configuration, starting fresh')
78+
return
79+
}
80+
81+
try {
82+
JSON.parse(data).forEach(function (server) {
83+
self._addServer(server)
84+
})
85+
} catch (e) {
86+
console.error('Manager load error: ' + e)
87+
}
88+
89+
self.getServers().map(function (server) {
90+
if (server.auto_start) {
91+
server.start()
92+
}
93+
})
94+
})
95+
}
96+
97+
Manager.prototype.save = function () {
98+
var data = []
99+
var self = this
100+
101+
this.serversArr.sort(function (a, b) {
102+
return a.title.toLowerCase().localeCompare(b.title.toLowerCase())
103+
})
104+
105+
this.serversHash = {}
106+
this.serversArr.forEach(function (server) {
107+
data.push({
108+
admin_password: server.admin_password,
109+
auto_start: server.auto_start,
110+
battle_eye: server.battle_eye,
111+
dedicatedServerId: server.dedicatedServerId,
112+
max_players: server.max_players,
113+
missions: server.missions,
114+
mods: server.mods,
115+
password: server.password,
116+
port: server.port,
117+
title: server.title
118+
})
119+
120+
self.serversHash[server.id] = server
121+
})
122+
123+
fs.writeFile(filePath, JSON.stringify(data), function (err) {
124+
if (err) {
125+
console.error('Manager save error: ' + err)
126+
} else {
127+
self.emit('servers')
128+
}
129+
})
130+
}
131+
132+
module.exports = Manager

0 commit comments

Comments
 (0)