diff --git a/squad-server/index.js b/squad-server/index.js index 43a68b56..a83c203e 100644 --- a/squad-server/index.js +++ b/squad-server/index.js @@ -198,12 +198,12 @@ export default class SquadServer extends EventEmitter { }); this.logParser.on('NEW_GAME', async (data) => { - data.layer = await Layers.getLayerByClassname(data.layerClassname); + await this.updateLayerInformation(); + data.layer = this.currentLayer; this.layerHistory.unshift({ layer: data.layer, time: data.time }); this.layerHistory = this.layerHistory.slice(0, this.layerHistoryMaxLength); - this.currentLayer = data.layer; await this.updateAdmins(); this.emit('NEW_GAME', data); }); @@ -505,8 +505,14 @@ export default class SquadServer extends EventEmitter { const nextMap = await this.rcon.getNextMap(); const nextMapToBeVoted = nextMap.layer === 'To be voted'; - const currentLayer = await Layers.getLayerById(currentMap.layer); - const nextLayer = nextMapToBeVoted ? null : await Layers.getLayerById(nextMap.layer); + const [currentLayer, currentTeams] = + await Layers.getLayerById(currentMap.layer, + currentMap.factionOne, + currentMap.factionTwo); + const [nextLayer, nextTeams] = + nextMapToBeVoted ? null : await Layers.getLayerById(nextMap.layer, + nextMap.factionOne, + nextMap.factionTwo); if (this.layerHistory.length === 0) { this.layerHistory.unshift({ layer: currentLayer, time: Date.now() }); @@ -514,7 +520,9 @@ export default class SquadServer extends EventEmitter { } this.currentLayer = currentLayer; + this.currentTeams = currentTeams; this.nextLayer = nextLayer; + this.nextTeams = nextTeams; this.nextLayerToBeVoted = nextMapToBeVoted; this.emit('UPDATED_LAYER_INFORMATION'); @@ -543,7 +551,7 @@ export default class SquadServer extends EventEmitter { const rawData = await this.rcon.execute(`ShowServerInfo`); Logger.verbose('SquadServer', 3, `Server information raw data`, rawData); const data = JSON.parse(rawData); - Logger.verbose('SquadServer', 2, `Server information data`, JSON.data); + Logger.verbose('SquadServer', 2, `Server information data`, data); const info = { raw: data, @@ -561,8 +569,8 @@ export default class SquadServer extends EventEmitter { currentLayer: data.MapName_s, nextLayer: data.NextLayer_s, - teamOne: data.TeamOne_s?.replace(new RegExp(data.MapName_s, 'i'), '') || '', - teamTwo: data.TeamTwo_s?.replace(new RegExp(data.MapName_s, 'i'), '') || '', + teamOne: data.TeamOne_s, + teamTwo: data.TeamTwo_s, matchTimeout: parseFloat(data.MatchTimeout_d), matchStartTime: this.getMatchStartTimeByPlaytime(data.PLAYTIME_I), @@ -579,13 +587,14 @@ export default class SquadServer extends EventEmitter { this.playerCount = info.playerCount; this.publicQueue = info.publicQueue; this.reserveQueue = info.reserveQueue; + this.unitNames = [data.TeamOne_s, data.TeamTwo_s]; this.matchTimeout = info.matchTimeout; this.matchStartTime = info.matchStartTime; this.gameVersion = info.gameVersion; - if (!this.currentLayer) this.currentLayer = Layers.getLayerByClassname(info.currentLayer); - if (!this.nextLayer) this.nextLayer = Layers.getLayerByClassname(info.nextLayer); + if (!this.currentLayer) + await this.updateLayerInformation(); this.emit('UPDATED_A2S_INFORMATION', info); this.emit('UPDATED_SERVER_INFORMATION', info); diff --git a/squad-server/layers/layer.js b/squad-server/layers/layer.js index 78bb0b08..7e02c2c1 100644 --- a/squad-server/layers/layer.js +++ b/squad-server/layers/layer.js @@ -13,30 +13,12 @@ export default class Layer { this.sizeType = data.mapSizeType; this.numberOfCapturePoints = parseInt(data.capturePoints); this.lighting = { - name: data.lighting, + type: data.persistentLightingType, classname: data.lightingLevel }; - this.teams = []; - for (const t of ['team1', 'team2']) { - this.teams.push({ - faction: data[t].faction, - name: data[t].teamSetupName, - tickets: data[t].tickets, - commander: data[t].commander, - vehicles: (data[t].vehicles || []).map((vehicle) => ({ - name: vehicle.type, - classname: vehicle.rawType, - count: vehicle.count, - spawnDelay: vehicle.delay, - respawnDelay: vehicle.respawnTime - })), - numberOfTanks: (data[t].vehicles || []).filter((v) => { - return v.icon.match(/_tank/); - }).length, - numberOfHelicopters: (data[t].vehicles || []).filter((v) => { - return v.icon.match(/helo/); - }).length - }); - } + this.factions = data.factions; + this.commander = data.commander; + this.tickets = [data.teamConfigs.team1.tickets, + data.teamConfigs.team2.tickets]; } } diff --git a/squad-server/layers/layers.js b/squad-server/layers/layers.js index 6e829014..23d515e8 100644 --- a/squad-server/layers/layers.js +++ b/squad-server/layers/layers.js @@ -22,14 +22,15 @@ class Layers { Logger.verbose('Layers', 1, 'Pulling layers...'); const response = await axios.get( - 'https://raw.githubusercontent.com/Squad-Wiki/squad-wiki-pipeline-map-data/master/completed_output/_Current%20Version/finished.json' + 'https://raw.githubusercontent.com/fantinodavide/SquadLayerList/main/layers.json' ); for (const layer of response.data.Maps) { this.layers.push(new Layer(layer)); } + this.units = response.data.Units; - Logger.verbose('Layers', 1, `Pulled ${this.layers.length} layers.`); + Logger.verbose('Layers', 1, `Pulled ${this.layers.length} layers and ${Object.keys(this.units).length} units.`); this.pulled = true; @@ -45,12 +46,50 @@ class Layers { return null; } - getLayerById(layerId) { - return this.getLayerByCondition((layer) => layer.layerid === layerId); + convertFactionToUnit(layer, factionName, teamIndex) { + // From factionName, in format "ADF+Mechanized", return the correct + // "ADF_XX_Mechanized" for current layer. + const factionParts = factionName.split("+"); + const matches = layer.factions.filter((f) => + f.factionId === factionParts[0] && + f.availableOnTeams.includes(teamIndex + 1) + ); + if (matches.length === 1) { + const faction = matches[0]; + if (factionParts.length === 1) { + return faction.defaultUnit; + } + else { + const unitParts = faction.defaultUnit.split('_', 2); + if (faction.types.includes(factionParts[1])) + return `${unitParts[0]}_${unitParts[1]}_${factionParts[1]}`; + else + return faction.defaultUnit; + } + } } - getLayerByClassname(classname) { - return this.getLayerByCondition((layer) => layer.classname === classname); + async getLayerById(layerId, factionOne, factionTwo) { + const layer = await this.getLayerByCondition((layer) => layer.layerid === layerId); + if (layer) { + const factions = [factionOne, factionTwo]; + let teams = []; + for (const teamIdx of [0, 1]) { + const faction = factions[teamIdx]; + const unitName = this.convertFactionToUnit(layer, faction, teamIdx); + const unit = this.units[unitName]; + teams[teamIdx] = { + faction: unit.factionID, + name: unit.displayName, + unitID: unitName, + unit: unit, + tickets: layer.tickets[teamIdx], + commander: layer.commander, + vehicles: unit.vehicles, + }; + } + return [layer, teams] + } } } diff --git a/squad-server/rcon.js b/squad-server/rcon.js index 2355d6d2..89365831 100644 --- a/squad-server/rcon.js +++ b/squad-server/rcon.js @@ -131,16 +131,23 @@ export default class SquadRcon extends Rcon { async getCurrentMap() { const response = await this.execute('ShowCurrentMap'); - const match = response.match(/^Current level is ([^,]*), layer is ([^,]*)/); - return { level: match[1], layer: match[2] }; + const match = response.match(/^Current level is ([^,]*), layer is ([^,]*), factions ([\w+]+) ([\w+]+)/); + return { + level: match[1], + layer: match[2], + factionOne: match[3], + factionTwo: match[4] + }; } async getNextMap() { const response = await this.execute('ShowNextMap'); - const match = response.match(/^Next level is ([^,]*), layer is ([^,]*)/); + const match = response.match(/^Next level is ([^,]*), layer is ([^,]*), factions ([\w+]+) ([\w+]+)/); return { level: match ? (match[1] !== '' ? match[1] : null) : null, - layer: match ? (match[2] !== 'To be voted' ? match[2] : null) : null + layer: match ? (match[2] !== 'To be voted' ? match[2] : null) : null, + factionOne: match[3], + factionTwo: match[4] }; }