mirror of
https://github.com/gamedig/node-gamedig.git
synced 2024-11-13 07:21:11 +01:00
chore: extract dayz from valve (#448)
This commit is contained in:
parent
6bfbc883be
commit
90b3c6044b
4 changed files with 187 additions and 155 deletions
|
@ -654,7 +654,7 @@ export const games = {
|
|||
options: {
|
||||
port: 2302,
|
||||
port_query_offset: 24714,
|
||||
protocol: 'valve'
|
||||
protocol: 'dayz'
|
||||
}
|
||||
},
|
||||
dayzmod: {
|
||||
|
|
182
protocols/dayz.js
Normal file
182
protocols/dayz.js
Normal file
|
@ -0,0 +1,182 @@
|
|||
import valve from './valve.js'
|
||||
import { Buffer } from 'node:buffer'
|
||||
|
||||
export default class dayz extends valve {
|
||||
async run (state) {
|
||||
if (!this.options.port) this.options.port = 27016
|
||||
await super.queryInfo(state)
|
||||
await super.queryChallenge()
|
||||
await super.queryPlayers(state)
|
||||
await this.queryRules(state)
|
||||
|
||||
this.processQueryInfo(state)
|
||||
await super.cleanup(state)
|
||||
}
|
||||
|
||||
async queryRules (state) {
|
||||
if (!this.options.requestRules) {
|
||||
return
|
||||
}
|
||||
|
||||
const rules = {}
|
||||
state.raw.rules = rules
|
||||
const dayZPayload = []
|
||||
|
||||
this.logger.debug('Requesting rules ...')
|
||||
|
||||
const b = await this.sendPacket(0x56, null, 0x45, true)
|
||||
if (b === null) return // timed out - the server probably has rules disabled
|
||||
|
||||
let dayZPayloadEnded = false
|
||||
|
||||
const reader = this.reader(b)
|
||||
const num = reader.uint(2)
|
||||
for (let i = 0; i < num; i++) {
|
||||
if (!dayZPayloadEnded) {
|
||||
const one = reader.uint(1)
|
||||
const two = reader.uint(1)
|
||||
const three = reader.uint(1)
|
||||
if (one !== 0 && two !== 0 && three === 0) {
|
||||
while (true) {
|
||||
const byte = reader.uint(1)
|
||||
if (byte === 0) break
|
||||
dayZPayload.push(byte)
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
reader.skip(-3)
|
||||
dayZPayloadEnded = true
|
||||
}
|
||||
}
|
||||
|
||||
const key = reader.string()
|
||||
rules[key] = reader.string()
|
||||
}
|
||||
|
||||
state.raw.dayzMods = this.readDayzMods(Buffer.from(dayZPayload))
|
||||
}
|
||||
|
||||
processQueryInfo (state) {
|
||||
// DayZ embeds some of the server information inside the tags attribute
|
||||
if (!state.raw.tags) { return }
|
||||
|
||||
state.raw.dlcEnabled = false
|
||||
state.raw.firstPerson = false
|
||||
for (const tag of state.raw.tags) {
|
||||
if (tag.startsWith('lqs')) {
|
||||
const value = parseInt(tag.replace('lqs', ''))
|
||||
if (!isNaN(value)) {
|
||||
state.raw.queue = value
|
||||
}
|
||||
}
|
||||
if (tag.includes('no3rd')) {
|
||||
state.raw.firstPerson = true
|
||||
}
|
||||
if (tag.includes('isDLC')) {
|
||||
state.raw.dlcEnabled = true
|
||||
}
|
||||
if (tag.includes(':')) {
|
||||
state.raw.time = tag
|
||||
}
|
||||
if (tag.startsWith('etm')) {
|
||||
const value = parseInt(tag.replace('etm', ''))
|
||||
if (!isNaN(value)) {
|
||||
state.raw.dayAcceleration = value
|
||||
}
|
||||
}
|
||||
if (tag.startsWith('entm')) {
|
||||
const value = parseInt(tag.replace('entm', ''))
|
||||
if (!isNaN(value)) {
|
||||
state.raw.nightAcceleration = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readDayzMods (/** Buffer */ buffer) {
|
||||
if (!buffer.length) {
|
||||
return {}
|
||||
}
|
||||
|
||||
this.logger.debug('DAYZ BUFFER')
|
||||
this.logger.debug(buffer)
|
||||
|
||||
const reader = this.reader(buffer)
|
||||
const version = this.readDayzByte(reader)
|
||||
const overflow = this.readDayzByte(reader)
|
||||
const dlc1 = this.readDayzByte(reader)
|
||||
const dlc2 = this.readDayzByte(reader)
|
||||
this.logger.debug('version ' + version)
|
||||
this.logger.debug('overflow ' + overflow)
|
||||
this.logger.debug('dlc1 ' + dlc1)
|
||||
this.logger.debug('dlc2 ' + dlc2)
|
||||
if (dlc1) {
|
||||
const unknown = this.readDayzUint(reader, 4) // ?
|
||||
this.logger.debug('unknown ' + unknown)
|
||||
}
|
||||
if (dlc2) {
|
||||
const unknown = this.readDayzUint(reader, 4) // ?
|
||||
this.logger.debug('unknown ' + unknown)
|
||||
}
|
||||
const mods = []
|
||||
mods.push(...this.readDayzModsSection(reader, true))
|
||||
mods.push(...this.readDayzModsSection(reader, false))
|
||||
this.logger.debug('dayz buffer rest:', reader.rest())
|
||||
return mods
|
||||
}
|
||||
|
||||
readDayzModsSection (/** Reader */ reader, withHeader) {
|
||||
const out = []
|
||||
const count = this.readDayzByte(reader)
|
||||
this.logger.debug('dayz mod section withHeader:' + withHeader + ' count:' + count)
|
||||
for (let i = 0; i < count; i++) {
|
||||
if (reader.done()) break
|
||||
const mod = {}
|
||||
if (withHeader) {
|
||||
mod.unknown = this.readDayzUint(reader, 4) // ?
|
||||
|
||||
// For some reason this is 4 on all of them, but doesn't exist on the last one? but only sometimes?
|
||||
const offset = reader.offset()
|
||||
const flag = this.readDayzByte(reader)
|
||||
if (flag !== 4) reader.setOffset(offset)
|
||||
|
||||
mod.workshopId = this.readDayzUint(reader, 4)
|
||||
}
|
||||
mod.title = this.readDayzString(reader)
|
||||
this.logger.debug(mod)
|
||||
out.push(mod)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
readDayzUint (reader, bytes) {
|
||||
const out = []
|
||||
for (let i = 0; i < bytes; i++) {
|
||||
out.push(this.readDayzByte(reader))
|
||||
}
|
||||
const buf = Buffer.from(out)
|
||||
const r2 = this.reader(buf)
|
||||
return r2.uint(bytes)
|
||||
}
|
||||
|
||||
readDayzByte (reader) {
|
||||
const byte = reader.uint(1)
|
||||
if (byte === 1) {
|
||||
const byte2 = reader.uint(1)
|
||||
if (byte2 === 1) return 1
|
||||
if (byte2 === 2) return 0
|
||||
if (byte2 === 3) return 0xff
|
||||
return 0 // ?
|
||||
}
|
||||
return byte
|
||||
}
|
||||
|
||||
readDayzString (reader) {
|
||||
const length = this.readDayzByte(reader)
|
||||
const out = []
|
||||
for (let i = 0; i < length; i++) {
|
||||
out.push(this.readDayzByte(reader))
|
||||
}
|
||||
return Buffer.from(out).toString('utf8')
|
||||
}
|
||||
}
|
|
@ -50,11 +50,12 @@ import ventrilo from './ventrilo.js'
|
|||
import warsow from './warsow.js'
|
||||
import beammpmaster from './beammpmaster.js'
|
||||
import beammp from './beammp.js'
|
||||
import dayz from './dayz.js'
|
||||
|
||||
export {
|
||||
armagetron, ase, asa, assettocorsa, battlefield, buildandshoot, cs2d, discord, doom3, eco, epic, ffow, fivem, gamespy1,
|
||||
gamespy2, gamespy3, geneshift, goldsrc, hexen2, jc2mp, kspdmp, mafia2mp, mafia2online, minecraft,
|
||||
minecraftbedrock, minecraftvanilla, mumble, mumbleping, nadeo, openttd, quake1, quake2, quake3, rfactor, samp,
|
||||
savage2, starmade, starsiege, teamspeak2, teamspeak3, terraria, tribes1, tribes1master, unreal2, ut3, valve,
|
||||
vcmp, ventrilo, warsow, eldewrito, beammpmaster, beammp
|
||||
vcmp, ventrilo, warsow, eldewrito, beammpmaster, beammp, dayz
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ const AppId = {
|
|||
Squad: 393380,
|
||||
Bat1944: 489940,
|
||||
Ship: 2400,
|
||||
DayZ: 221100,
|
||||
Rust: 252490,
|
||||
CSGO: 730,
|
||||
CS_Source: 240,
|
||||
|
@ -132,43 +131,6 @@ export default class valve extends Core {
|
|||
this.goldsrcSplits = true
|
||||
}
|
||||
|
||||
// DayZ embeds some of the server information inside the tags attribute
|
||||
if (appId === AppId.DayZ) {
|
||||
if (state.raw.tags) {
|
||||
state.raw.dlcEnabled = false
|
||||
state.raw.firstPerson = false
|
||||
for (const tag of state.raw.tags) {
|
||||
if (tag.startsWith('lqs')) {
|
||||
const value = parseInt(tag.replace('lqs', ''))
|
||||
if (!isNaN(value)) {
|
||||
state.raw.queue = value
|
||||
}
|
||||
}
|
||||
if (tag.includes('no3rd')) {
|
||||
state.raw.firstPerson = true
|
||||
}
|
||||
if (tag.includes('isDLC')) {
|
||||
state.raw.dlcEnabled = true
|
||||
}
|
||||
if (tag.includes(':')) {
|
||||
state.raw.time = tag
|
||||
}
|
||||
if (tag.startsWith('etm')) {
|
||||
const value = parseInt(tag.replace('etm', ''))
|
||||
if (!isNaN(value)) {
|
||||
state.raw.dayAcceleration = value
|
||||
}
|
||||
}
|
||||
if (tag.startsWith('entm')) {
|
||||
const value = parseInt(tag.replace('entm', ''))
|
||||
if (!isNaN(value)) {
|
||||
state.raw.nightAcceleration = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (appId === AppId.Rust) {
|
||||
if (state.raw.tags) {
|
||||
for (const tag of state.raw.tags) {
|
||||
|
@ -250,7 +212,6 @@ export default class valve extends Core {
|
|||
|
||||
const rules = {}
|
||||
state.raw.rules = rules
|
||||
const dayZPayload = []
|
||||
|
||||
this.logger.debug('Requesting rules ...')
|
||||
|
||||
|
@ -260,38 +221,17 @@ export default class valve extends Core {
|
|||
const reader = this.reader(b)
|
||||
while (!reader.done()) {
|
||||
const key = reader.string()
|
||||
const value = reader.string()
|
||||
rules[key] = value
|
||||
rules[key] = reader.string()
|
||||
}
|
||||
} else {
|
||||
const b = await this.sendPacket(0x56, null, 0x45, true)
|
||||
if (b === null) return // timed out - the server probably has rules disabled
|
||||
|
||||
let dayZPayloadEnded = false
|
||||
|
||||
const reader = this.reader(b)
|
||||
const num = reader.uint(2)
|
||||
for (let i = 0; i < num; i++) {
|
||||
if (appId === AppId.DayZ && !dayZPayloadEnded) {
|
||||
const one = reader.uint(1)
|
||||
const two = reader.uint(1)
|
||||
const three = reader.uint(1)
|
||||
if (one !== 0 && two !== 0 && three === 0) {
|
||||
while (true) {
|
||||
const byte = reader.uint(1)
|
||||
if (byte === 0) break
|
||||
dayZPayload.push(byte)
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
reader.skip(-3)
|
||||
dayZPayloadEnded = true
|
||||
}
|
||||
}
|
||||
|
||||
const key = reader.string()
|
||||
const value = reader.string()
|
||||
rules[key] = value
|
||||
rules[key] = reader.string()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -323,97 +263,6 @@ export default class valve extends Core {
|
|||
state.password = true
|
||||
}
|
||||
}
|
||||
|
||||
if (appId === AppId.DayZ) {
|
||||
state.raw.dayzMods = this.readDayzMods(Buffer.from(dayZPayload))
|
||||
}
|
||||
}
|
||||
|
||||
readDayzMods (/** Buffer */ buffer) {
|
||||
if (!buffer.length) {
|
||||
return {}
|
||||
}
|
||||
|
||||
this.logger.debug('DAYZ BUFFER')
|
||||
this.logger.debug(buffer)
|
||||
|
||||
const reader = this.reader(buffer)
|
||||
const version = this.readDayzByte(reader)
|
||||
const overflow = this.readDayzByte(reader)
|
||||
const dlc1 = this.readDayzByte(reader)
|
||||
const dlc2 = this.readDayzByte(reader)
|
||||
this.logger.debug('version ' + version)
|
||||
this.logger.debug('overflow ' + overflow)
|
||||
this.logger.debug('dlc1 ' + dlc1)
|
||||
this.logger.debug('dlc2 ' + dlc2)
|
||||
if (dlc1) {
|
||||
const unknown = this.readDayzUint(reader, 4) // ?
|
||||
this.logger.debug('unknown ' + unknown)
|
||||
}
|
||||
if (dlc2) {
|
||||
const unknown = this.readDayzUint(reader, 4) // ?
|
||||
this.logger.debug('unknown ' + unknown)
|
||||
}
|
||||
const mods = []
|
||||
mods.push(...this.readDayzModsSection(reader, true))
|
||||
mods.push(...this.readDayzModsSection(reader, false))
|
||||
this.logger.debug('dayz buffer rest:', reader.rest())
|
||||
return mods
|
||||
}
|
||||
|
||||
readDayzModsSection (/** Reader */ reader, withHeader) {
|
||||
const out = []
|
||||
const count = this.readDayzByte(reader)
|
||||
this.logger.debug('dayz mod section withHeader:' + withHeader + ' count:' + count)
|
||||
for (let i = 0; i < count; i++) {
|
||||
if (reader.done()) break
|
||||
const mod = {}
|
||||
if (withHeader) {
|
||||
mod.unknown = this.readDayzUint(reader, 4) // ?
|
||||
|
||||
// For some reason this is 4 on all of them, but doesn't exist on the last one? but only sometimes?
|
||||
const offset = reader.offset()
|
||||
const flag = this.readDayzByte(reader)
|
||||
if (flag !== 4) reader.setOffset(offset)
|
||||
|
||||
mod.workshopId = this.readDayzUint(reader, 4)
|
||||
}
|
||||
mod.title = this.readDayzString(reader)
|
||||
this.logger.debug(mod)
|
||||
out.push(mod)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
readDayzUint (reader, bytes) {
|
||||
const out = []
|
||||
for (let i = 0; i < bytes; i++) {
|
||||
out.push(this.readDayzByte(reader))
|
||||
}
|
||||
const buf = Buffer.from(out)
|
||||
const r2 = this.reader(buf)
|
||||
return r2.uint(bytes)
|
||||
}
|
||||
|
||||
readDayzByte (reader) {
|
||||
const byte = reader.uint(1)
|
||||
if (byte === 1) {
|
||||
const byte2 = reader.uint(1)
|
||||
if (byte2 === 1) return 1
|
||||
if (byte2 === 2) return 0
|
||||
if (byte2 === 3) return 0xff
|
||||
return 0 // ?
|
||||
}
|
||||
return byte
|
||||
}
|
||||
|
||||
readDayzString (reader) {
|
||||
const length = this.readDayzByte(reader)
|
||||
const out = []
|
||||
for (let i = 0; i < length; i++) {
|
||||
out.push(this.readDayzByte(reader))
|
||||
}
|
||||
return Buffer.from(out).toString('utf8')
|
||||
}
|
||||
|
||||
async cleanup (/** Results */ state) {
|
||||
|
|
Loading…
Reference in a new issue