Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arma Reforger support #223

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ A simple to use web admin panel for Arma servers.
- cwa (does not support linux)
- ofp
- ofpresistance
- reforger

## Config

Expand Down
10 changes: 10 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var express = require('express')
var bodyParser = require('body-parser')
var fs = require('fs.extra')
var morgan = require('morgan')
var path = require('path')
var serveStatic = require('serve-static')
Expand All @@ -15,6 +16,15 @@ var Mods = require('./lib/mods')
var Logs = require('./lib/logs')
var Settings = require('./lib/settings')

if (config.game === 'reforger') {
Logs = require('./lib/reforger/logs')
Manager = require('./lib/reforger/manager')
Missions = require('./lib/reforger/missions')
Mods = require('./lib/reforger/mods')

fs.mkdirp(config.reforger.profiles) // Needs to be created in advance or game will store profiles elsewhere
}

var app = express()
var server = require('http').Server(app)
var io = require('socket.io')(server)
Expand Down
17 changes: 16 additions & 1 deletion config.docker.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
for (var environmentVariable of ['GAME_TYPE', 'GAME_PATH']) {
['GAME_TYPE', 'GAME_PATH'].forEach(function (environmentVariable) {
if (!process.env[environmentVariable]) {
console.log('Missing required environment variable "' + environmentVariable + '"')
process.exit(1)
}
})

if (process.env.GAME_TYPE === 'reforger') {
['REFORGER_CONFIGS', 'REFORGER_LOGS', 'REFORGER_PROFILES', 'REFORGER_WORKSHOP'].forEach(function (environmentVariable) {
if (!process.env[environmentVariable]) {
console.log('Missing required environment variable "' + environmentVariable + '"')
process.exit(1)
}
})
}

module.exports = {
Expand All @@ -19,6 +28,12 @@ module.exports = {
username: process.env.AUTH_USERNAME,
password: process.env.AUTH_PROCESS
},
reforger: {
configs: process.env.REFORGER_CONFIGS,
logs: process.env.REFORGER_LOGS,
profiles: process.env.REFORGER_PROFILES,
workshop: process.env.REFORGER_WORKSHOP
},
prefix: process.env.SERVER_PREFIX,
suffix: process.env.SERVER_SUFFIX,
logFormat: process.env.LOG_FORMAT || 'dev'
Expand Down
8 changes: 7 additions & 1 deletion config.js.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = {
game: 'arma3', // arma3, arma2oa, arma2, arma1, cwa, ofpresistance, ofp
game: 'arma3', // arma3, arma2oa, arma2, arma1, cwa, ofpresistance, ofp, reforger
path: 'path-to-arma3-directory',
port: 3000,
host: '0.0.0.0', // Can be either an IP or a Hostname
Expand All @@ -9,6 +9,12 @@ module.exports = {
'-noSound',
'-world=empty'
],
reforger: {
configs: 'path-to-configs-folder', // Folder where server config files will be stored
logs: 'path-to-logs-folder', // Folder where server log files will be stored
profiles: 'path-to-profiles-folder', // Folder where logs and persistence data will be stored. Each server will create a subfolder.
workshop: 'path-to-workshop-folder' // Folder where workshop mods will be stored
},
serverMods: [ // Mods used exclusively by server and not shared with clients
'@mod1',
'@mod2',
Expand Down
7 changes: 3 additions & 4 deletions lib/mods/folderSize.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ var fs = require('fs')
var glob = require('glob')
var path = require('path')

module.exports = function (modPath, config, callback) {
var basePath = path.resolve(config.path, modPath)
module.exports = function (modPath, callback) {
var total = 0
glob('**/*', { cwd: basePath, dot: true }, function (err, files) {
glob('**/*', { cwd: modPath, dot: true }, function (err, files) {
if (err) {
return callback(err, 0)
}

async.forEach(files, function (file, cb) {
fs.stat(path.join(basePath, file), function stat (err, stats) {
fs.stat(path.join(modPath, file), function stat (err, stats) {
if (!err && (stats.isFile() || stats.isSymbolicLink())) {
var size = stats.size || 0
total += size
Expand Down
4 changes: 3 additions & 1 deletion lib/mods/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ Mods.prototype.resolveModData = function (modPath, cb) {
var self = this
async.parallel({
folderSize: function (cb) {
folderSize(modPath, self.config, cb)
var basePath = path.resolve(self.config.path, modPath)
folderSize(basePath, cb)
},
modFile: function (cb) {
modFile(modPath, self.config, cb)
Expand All @@ -70,6 +71,7 @@ Mods.prototype.resolveModData = function (modPath, cb) {
}

cb(null, {
id: modPath,
name: modPath,
size: results.folderSize,
formattedSize: filesize(results.folderSize),
Expand Down
99 changes: 99 additions & 0 deletions lib/reforger/logs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
var async = require('async')
var filesize = require('filesize')
var fs = require('fs.extra')
var glob = require('glob')
var path = require('path')

var Logs = function (config) {
this.config = config
}

Logs.prototype.delete = function (filename, callback) {
callback = callback || function () {}

this.getLogFile(filename, function (err, logFile) {
if (err) {
return callback(err)
} else {
if (logFile && logFile.path) {
fs.unlink(logFile.path, callback)
} else {
return callback(new Error('File not found'))
}
}
})
}

Logs.prototype.logsPath = function () {
return this.config.reforger.logs
}

Logs.prototype.logFiles = function (callback) {
var directory = this.logsPath()

if (directory === null) {
return callback(null, [])
}

glob('**/*.log', { cwd: directory }, function (err, files) {
if (err) {
callback(err)
return
}

files = files.map(function (file) {
return {
name: file,
path: path.join(directory, file)
}
})

async.filter(files, function (file, cb) {
fs.stat(file.path, function (err, stat) {
if (err) {
return cb(err)
}

file.created = stat.birthtime.toISOString()
file.modified = stat.mtime.toISOString()
file.formattedSize = filesize(stat.size)
file.size = stat.size
cb(null, stat.isFile())
})
}, function (err, files) {
if (err) {
return callback(err)
}

files.sort(function (a, b) {
return b.created.localeCompare(a.created) // Descending order
})

callback(null, files)
})
})
}

Logs.prototype.getLogFile = function (filename, callback) {
this.logFiles(function (err, files) {
if (err) {
callback(err)
} else {
var validLogs = files.filter(function (file) {
return file.name === filename
})

if (validLogs.length > 0) {
callback(null, validLogs[0])
} else {
callback(null, null)
}
}
})
}

Logs.prototype.readLogFile = function (filename, callback) {
fs.readFile(filename, callback)
}

module.exports = Logs
132 changes: 132 additions & 0 deletions lib/reforger/manager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
var events = require('events')
var fs = require('fs')

var Server = require('./server')

var filePath = 'servers.json'

var Manager = function (config, logs) {
this.config = config
this.logs = logs
this.serversArr = []
this.serversHash = {}
}

Manager.prototype = new events.EventEmitter()

Manager.prototype.addServer = function (options) {
var server = this._addServer(options)
this.save()
return server
}

Manager.prototype.removeServer = function (id) {
var server = this.serversHash[id]

if (!server) {
return {}
}

var index = this.serversArr.indexOf(server)
if (index > -1) {
this.serversArr.splice(index, 1)
}
this.save()

if (server.pid) {
server.stop()
}

return server
}

Manager.prototype._addServer = function (data) {
var server = new Server(this.config, this.logs, data)
this.serversArr.push(server)
this.serversArr.sort(function (a, b) {
return a.title.localeCompare(b.title)
})
this.serversHash[server.id] = server

var self = this
var save = function () {
self.save()
}
var statusChanged = function () {
self.emit('servers')
}
server.on('save', save)
server.on('state', statusChanged)

return server
}

Manager.prototype.getServer = function (id) {
return this.serversHash[id]
}

Manager.prototype.getServers = function () {
return this.serversArr
}

Manager.prototype.load = function () {
var self = this

fs.readFile(filePath, function (err, data) {
if (err) {
console.log('Could not load any existing servers configuration, starting fresh')
return
}

try {
JSON.parse(data).forEach(function (server) {
self._addServer(server)
})
} catch (e) {
console.error('Manager load error: ' + e)
}

self.getServers().map(function (server) {
if (server.auto_start) {
server.start()
}
})
})
}

Manager.prototype.save = function () {
var data = []
var self = this

this.serversArr.sort(function (a, b) {
return a.title.toLowerCase().localeCompare(b.title.toLowerCase())
})

this.serversHash = {}
this.serversArr.forEach(function (server) {
data.push({
admin_password: server.admin_password,
auto_start: server.auto_start,
battle_eye: server.battle_eye,
dedicatedServerId: server.dedicatedServerId,
max_players: server.max_players,
missions: server.missions,
mods: server.mods,
password: server.password,
port: server.port,
title: server.title
})

self.serversHash[server.id] = server
})

fs.writeFile(filePath, JSON.stringify(data), function (err) {
if (err) {
console.error('Manager save error: ' + err)
} else {
self.emit('servers')
}
})
}

module.exports = Manager
Loading