mirror of
https://github.com/tribufu/node-gamedig
synced 2026-05-06 15:17:36 +00:00
chore: Convert all files to LF endings (#400)
* Convert to LF? * Modify gitattributes * Force LF * Git --renormalize * Update .gitattributes to enforce eol=lf * Redo CRLF -> LF on remaining files
This commit is contained in:
parent
a8bc7521f6
commit
cee42e7a88
65 changed files with 5697 additions and 5697 deletions
|
|
@ -1,197 +1,197 @@
|
|||
import Core from './core.js'
|
||||
|
||||
export default class gamespy3 extends Core {
|
||||
constructor () {
|
||||
super()
|
||||
this.sessionId = 1
|
||||
this.encoding = 'latin1'
|
||||
this.byteorder = 'be'
|
||||
this.useOnlySingleSplit = false
|
||||
this.isJc2mp = false
|
||||
}
|
||||
|
||||
async run (state) {
|
||||
const buffer = await this.sendPacket(9, false, false, false)
|
||||
const reader = this.reader(buffer)
|
||||
let challenge = parseInt(reader.string())
|
||||
this.logger.debug('Received challenge key: ' + challenge)
|
||||
if (challenge === 0) {
|
||||
// Some servers send us a 0 if they don't want a challenge key used
|
||||
// BF2 does this.
|
||||
challenge = null
|
||||
}
|
||||
|
||||
let requestPayload
|
||||
if (this.isJc2mp) {
|
||||
// they completely alter the protocol. because why not.
|
||||
requestPayload = Buffer.from([0xff, 0xff, 0xff, 0x02])
|
||||
} else {
|
||||
requestPayload = Buffer.from([0xff, 0xff, 0xff, 0x01])
|
||||
}
|
||||
/** @type Buffer[] */
|
||||
const packets = await this.sendPacket(0, challenge, requestPayload, true)
|
||||
|
||||
// iterate over the received packets
|
||||
// the first packet will start off with k/v pairs, followed with data fields
|
||||
// the following packets will only have data fields
|
||||
state.raw.playerTeamInfo = {}
|
||||
|
||||
for (let iPacket = 0; iPacket < packets.length; iPacket++) {
|
||||
const packet = packets[iPacket]
|
||||
const reader = this.reader(packet)
|
||||
|
||||
this.logger.debug('Parsing packet #' + iPacket)
|
||||
this.logger.debug(packet)
|
||||
|
||||
// Parse raw server key/values
|
||||
|
||||
if (iPacket === 0) {
|
||||
while (!reader.done()) {
|
||||
const key = reader.string()
|
||||
if (!key) break
|
||||
|
||||
let value = reader.string()
|
||||
while (value.match(/^p[0-9]+$/)) {
|
||||
// fix a weird ut3 bug where some keys don't have values
|
||||
value = reader.string()
|
||||
}
|
||||
|
||||
state.raw[key] = value
|
||||
this.logger.debug(key + ' = ' + value)
|
||||
}
|
||||
}
|
||||
|
||||
// Parse player, team, item array state
|
||||
|
||||
if (this.isJc2mp) {
|
||||
state.raw.numPlayers2 = reader.uint(2)
|
||||
while (!reader.done()) {
|
||||
const player = {}
|
||||
player.name = reader.string()
|
||||
player.steamid = reader.string()
|
||||
player.ping = reader.uint(2)
|
||||
state.players.push(player)
|
||||
}
|
||||
} else {
|
||||
while (!reader.done()) {
|
||||
if (reader.uint(1) <= 2) continue
|
||||
reader.skip(-1)
|
||||
const fieldId = reader.string()
|
||||
if (!fieldId) continue
|
||||
const fieldIdSplit = fieldId.split('_')
|
||||
const fieldName = fieldIdSplit[0]
|
||||
const itemType = fieldIdSplit.length > 1 ? fieldIdSplit[1] : 'no_'
|
||||
|
||||
if (!(itemType in state.raw.playerTeamInfo)) {
|
||||
state.raw.playerTeamInfo[itemType] = []
|
||||
}
|
||||
const items = state.raw.playerTeamInfo[itemType]
|
||||
|
||||
let offset = reader.uint(1)
|
||||
|
||||
this.logger.debug(() => 'Parsing new field: itemType=' + itemType + ' fieldName=' + fieldName + ' startOffset=' + offset)
|
||||
|
||||
while (!reader.done()) {
|
||||
const item = reader.string()
|
||||
if (!item) break
|
||||
|
||||
while (items.length <= offset) { items.push({}) }
|
||||
items[offset][fieldName] = item
|
||||
this.logger.debug('* ' + item)
|
||||
offset++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Turn all that raw state into something useful
|
||||
|
||||
if ('hostname' in state.raw) state.name = state.raw.hostname
|
||||
else if ('servername' in state.raw) state.name = state.raw.servername
|
||||
if ('mapname' in state.raw) state.map = state.raw.mapname
|
||||
if (state.raw.password === '1') state.password = true
|
||||
if ('maxplayers' in state.raw) state.maxplayers = parseInt(state.raw.maxplayers)
|
||||
if ('hostport' in state.raw) state.gamePort = parseInt(state.raw.hostport)
|
||||
|
||||
if ('' in state.raw.playerTeamInfo) {
|
||||
for (const playerInfo of state.raw.playerTeamInfo['']) {
|
||||
const player = {}
|
||||
for (const from of Object.keys(playerInfo)) {
|
||||
let key = from
|
||||
let value = playerInfo[from]
|
||||
|
||||
if (key === 'player') key = 'name'
|
||||
if (key === 'score' || key === 'ping' || key === 'team' || key === 'deaths' || key === 'pid') value = parseInt(value)
|
||||
player[key] = value
|
||||
}
|
||||
state.players.push(player)
|
||||
}
|
||||
}
|
||||
|
||||
if ('numplayers' in state.raw) state.numplayers = parseInt(state.raw.numplayers)
|
||||
else state.numplayers = state.players.length
|
||||
}
|
||||
|
||||
async sendPacket (type, challenge, payload, assemble) {
|
||||
const challengeLength = challenge === null ? 0 : 4
|
||||
const payloadLength = payload ? payload.length : 0
|
||||
|
||||
const b = Buffer.alloc(7 + challengeLength + payloadLength)
|
||||
b.writeUInt8(0xFE, 0)
|
||||
b.writeUInt8(0xFD, 1)
|
||||
b.writeUInt8(type, 2)
|
||||
b.writeUInt32BE(this.sessionId, 3)
|
||||
if (challengeLength) b.writeInt32BE(challenge, 7)
|
||||
if (payloadLength) payload.copy(b, 7 + challengeLength)
|
||||
|
||||
let numPackets = 0
|
||||
const packets = {}
|
||||
return await this.udpSend(b, (buffer) => {
|
||||
const reader = this.reader(buffer)
|
||||
const iType = reader.uint(1)
|
||||
if (iType !== type) {
|
||||
this.logger.debug('Skipping packet, type mismatch')
|
||||
return
|
||||
}
|
||||
const iSessionId = reader.uint(4)
|
||||
if (iSessionId !== this.sessionId) {
|
||||
this.logger.debug('Skipping packet, session id mismatch')
|
||||
return
|
||||
}
|
||||
|
||||
if (!assemble) {
|
||||
return reader.rest()
|
||||
}
|
||||
if (this.useOnlySingleSplit) {
|
||||
// has split headers, but they are worthless and only one packet is used
|
||||
reader.skip(11)
|
||||
return [reader.rest()]
|
||||
}
|
||||
|
||||
reader.skip(9) // filler data -- usually set to 'splitnum\0'
|
||||
let id = reader.uint(1)
|
||||
const last = (id & 0x80)
|
||||
id = id & 0x7f
|
||||
if (last) numPackets = id + 1
|
||||
|
||||
reader.skip(1) // "another 'packet number' byte, but isn't understood."
|
||||
|
||||
packets[id] = reader.rest()
|
||||
if (this.debug) {
|
||||
this.logger.debug('Received packet #' + id + (last ? ' (last)' : ''))
|
||||
}
|
||||
|
||||
if (!numPackets || Object.keys(packets).length !== numPackets) return
|
||||
|
||||
// assemble the parts
|
||||
const list = []
|
||||
for (let i = 0; i < numPackets; i++) {
|
||||
if (!(i in packets)) {
|
||||
throw new Error('Missing packet #' + i)
|
||||
}
|
||||
list.push(packets[i])
|
||||
}
|
||||
return list
|
||||
})
|
||||
}
|
||||
}
|
||||
import Core from './core.js'
|
||||
|
||||
export default class gamespy3 extends Core {
|
||||
constructor () {
|
||||
super()
|
||||
this.sessionId = 1
|
||||
this.encoding = 'latin1'
|
||||
this.byteorder = 'be'
|
||||
this.useOnlySingleSplit = false
|
||||
this.isJc2mp = false
|
||||
}
|
||||
|
||||
async run (state) {
|
||||
const buffer = await this.sendPacket(9, false, false, false)
|
||||
const reader = this.reader(buffer)
|
||||
let challenge = parseInt(reader.string())
|
||||
this.logger.debug('Received challenge key: ' + challenge)
|
||||
if (challenge === 0) {
|
||||
// Some servers send us a 0 if they don't want a challenge key used
|
||||
// BF2 does this.
|
||||
challenge = null
|
||||
}
|
||||
|
||||
let requestPayload
|
||||
if (this.isJc2mp) {
|
||||
// they completely alter the protocol. because why not.
|
||||
requestPayload = Buffer.from([0xff, 0xff, 0xff, 0x02])
|
||||
} else {
|
||||
requestPayload = Buffer.from([0xff, 0xff, 0xff, 0x01])
|
||||
}
|
||||
/** @type Buffer[] */
|
||||
const packets = await this.sendPacket(0, challenge, requestPayload, true)
|
||||
|
||||
// iterate over the received packets
|
||||
// the first packet will start off with k/v pairs, followed with data fields
|
||||
// the following packets will only have data fields
|
||||
state.raw.playerTeamInfo = {}
|
||||
|
||||
for (let iPacket = 0; iPacket < packets.length; iPacket++) {
|
||||
const packet = packets[iPacket]
|
||||
const reader = this.reader(packet)
|
||||
|
||||
this.logger.debug('Parsing packet #' + iPacket)
|
||||
this.logger.debug(packet)
|
||||
|
||||
// Parse raw server key/values
|
||||
|
||||
if (iPacket === 0) {
|
||||
while (!reader.done()) {
|
||||
const key = reader.string()
|
||||
if (!key) break
|
||||
|
||||
let value = reader.string()
|
||||
while (value.match(/^p[0-9]+$/)) {
|
||||
// fix a weird ut3 bug where some keys don't have values
|
||||
value = reader.string()
|
||||
}
|
||||
|
||||
state.raw[key] = value
|
||||
this.logger.debug(key + ' = ' + value)
|
||||
}
|
||||
}
|
||||
|
||||
// Parse player, team, item array state
|
||||
|
||||
if (this.isJc2mp) {
|
||||
state.raw.numPlayers2 = reader.uint(2)
|
||||
while (!reader.done()) {
|
||||
const player = {}
|
||||
player.name = reader.string()
|
||||
player.steamid = reader.string()
|
||||
player.ping = reader.uint(2)
|
||||
state.players.push(player)
|
||||
}
|
||||
} else {
|
||||
while (!reader.done()) {
|
||||
if (reader.uint(1) <= 2) continue
|
||||
reader.skip(-1)
|
||||
const fieldId = reader.string()
|
||||
if (!fieldId) continue
|
||||
const fieldIdSplit = fieldId.split('_')
|
||||
const fieldName = fieldIdSplit[0]
|
||||
const itemType = fieldIdSplit.length > 1 ? fieldIdSplit[1] : 'no_'
|
||||
|
||||
if (!(itemType in state.raw.playerTeamInfo)) {
|
||||
state.raw.playerTeamInfo[itemType] = []
|
||||
}
|
||||
const items = state.raw.playerTeamInfo[itemType]
|
||||
|
||||
let offset = reader.uint(1)
|
||||
|
||||
this.logger.debug(() => 'Parsing new field: itemType=' + itemType + ' fieldName=' + fieldName + ' startOffset=' + offset)
|
||||
|
||||
while (!reader.done()) {
|
||||
const item = reader.string()
|
||||
if (!item) break
|
||||
|
||||
while (items.length <= offset) { items.push({}) }
|
||||
items[offset][fieldName] = item
|
||||
this.logger.debug('* ' + item)
|
||||
offset++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Turn all that raw state into something useful
|
||||
|
||||
if ('hostname' in state.raw) state.name = state.raw.hostname
|
||||
else if ('servername' in state.raw) state.name = state.raw.servername
|
||||
if ('mapname' in state.raw) state.map = state.raw.mapname
|
||||
if (state.raw.password === '1') state.password = true
|
||||
if ('maxplayers' in state.raw) state.maxplayers = parseInt(state.raw.maxplayers)
|
||||
if ('hostport' in state.raw) state.gamePort = parseInt(state.raw.hostport)
|
||||
|
||||
if ('' in state.raw.playerTeamInfo) {
|
||||
for (const playerInfo of state.raw.playerTeamInfo['']) {
|
||||
const player = {}
|
||||
for (const from of Object.keys(playerInfo)) {
|
||||
let key = from
|
||||
let value = playerInfo[from]
|
||||
|
||||
if (key === 'player') key = 'name'
|
||||
if (key === 'score' || key === 'ping' || key === 'team' || key === 'deaths' || key === 'pid') value = parseInt(value)
|
||||
player[key] = value
|
||||
}
|
||||
state.players.push(player)
|
||||
}
|
||||
}
|
||||
|
||||
if ('numplayers' in state.raw) state.numplayers = parseInt(state.raw.numplayers)
|
||||
else state.numplayers = state.players.length
|
||||
}
|
||||
|
||||
async sendPacket (type, challenge, payload, assemble) {
|
||||
const challengeLength = challenge === null ? 0 : 4
|
||||
const payloadLength = payload ? payload.length : 0
|
||||
|
||||
const b = Buffer.alloc(7 + challengeLength + payloadLength)
|
||||
b.writeUInt8(0xFE, 0)
|
||||
b.writeUInt8(0xFD, 1)
|
||||
b.writeUInt8(type, 2)
|
||||
b.writeUInt32BE(this.sessionId, 3)
|
||||
if (challengeLength) b.writeInt32BE(challenge, 7)
|
||||
if (payloadLength) payload.copy(b, 7 + challengeLength)
|
||||
|
||||
let numPackets = 0
|
||||
const packets = {}
|
||||
return await this.udpSend(b, (buffer) => {
|
||||
const reader = this.reader(buffer)
|
||||
const iType = reader.uint(1)
|
||||
if (iType !== type) {
|
||||
this.logger.debug('Skipping packet, type mismatch')
|
||||
return
|
||||
}
|
||||
const iSessionId = reader.uint(4)
|
||||
if (iSessionId !== this.sessionId) {
|
||||
this.logger.debug('Skipping packet, session id mismatch')
|
||||
return
|
||||
}
|
||||
|
||||
if (!assemble) {
|
||||
return reader.rest()
|
||||
}
|
||||
if (this.useOnlySingleSplit) {
|
||||
// has split headers, but they are worthless and only one packet is used
|
||||
reader.skip(11)
|
||||
return [reader.rest()]
|
||||
}
|
||||
|
||||
reader.skip(9) // filler data -- usually set to 'splitnum\0'
|
||||
let id = reader.uint(1)
|
||||
const last = (id & 0x80)
|
||||
id = id & 0x7f
|
||||
if (last) numPackets = id + 1
|
||||
|
||||
reader.skip(1) // "another 'packet number' byte, but isn't understood."
|
||||
|
||||
packets[id] = reader.rest()
|
||||
if (this.debug) {
|
||||
this.logger.debug('Received packet #' + id + (last ? ' (last)' : ''))
|
||||
}
|
||||
|
||||
if (!numPackets || Object.keys(packets).length !== numPackets) return
|
||||
|
||||
// assemble the parts
|
||||
const list = []
|
||||
for (let i = 0; i < numPackets; i++) {
|
||||
if (!(i in packets)) {
|
||||
throw new Error('Missing packet #' + i)
|
||||
}
|
||||
list.push(packets[i])
|
||||
}
|
||||
return list
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue