gamedigz 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/GAMES_LIST.md +453 -0
- package/LICENSE +21 -0
- package/README.md +144 -0
- package/bin/gamedig.js +79 -0
- package/lib/DnsResolver.js +76 -0
- package/lib/GlobalUdpSocket.js +69 -0
- package/lib/HexUtil.js +20 -0
- package/lib/Logger.js +45 -0
- package/lib/Promises.js +18 -0
- package/lib/ProtocolResolver.js +7 -0
- package/lib/QueryRunner.js +95 -0
- package/lib/Results.js +32 -0
- package/lib/game-resolver.js +17 -0
- package/lib/gamedig.js +23 -0
- package/lib/games.js +2747 -0
- package/lib/index.js +5 -0
- package/lib/reader.js +172 -0
- package/package.json +74 -0
- package/protocols/armagetron.js +65 -0
- package/protocols/asa.js +12 -0
- package/protocols/ase.js +45 -0
- package/protocols/assettocorsa.js +40 -0
- package/protocols/battlefield.js +162 -0
- package/protocols/beammp.js +32 -0
- package/protocols/beammpmaster.js +17 -0
- package/protocols/buildandshoot.js +55 -0
- package/protocols/core.js +349 -0
- package/protocols/cs2d.js +65 -0
- package/protocols/dayz.js +196 -0
- package/protocols/discord.js +29 -0
- package/protocols/doom3.js +148 -0
- package/protocols/eco.js +20 -0
- package/protocols/eldewrito.js +21 -0
- package/protocols/epic.js +95 -0
- package/protocols/ffow.js +38 -0
- package/protocols/fivem.js +33 -0
- package/protocols/gamespy1.js +181 -0
- package/protocols/gamespy2.js +144 -0
- package/protocols/gamespy3.js +197 -0
- package/protocols/geneshift.js +46 -0
- package/protocols/goldsrc.js +8 -0
- package/protocols/hexen2.js +14 -0
- package/protocols/index.js +61 -0
- package/protocols/jc2mp.js +16 -0
- package/protocols/kspdmp.js +28 -0
- package/protocols/mafia2mp.js +41 -0
- package/protocols/mafia2online.js +9 -0
- package/protocols/minecraft.js +102 -0
- package/protocols/minecraftbedrock.js +72 -0
- package/protocols/minecraftvanilla.js +87 -0
- package/protocols/mumble.js +39 -0
- package/protocols/mumbleping.js +24 -0
- package/protocols/nadeo.js +86 -0
- package/protocols/openttd.js +127 -0
- package/protocols/quake1.js +9 -0
- package/protocols/quake2.js +88 -0
- package/protocols/quake3.js +24 -0
- package/protocols/rfactor.js +69 -0
- package/protocols/samp.js +102 -0
- package/protocols/savage2.js +25 -0
- package/protocols/starmade.js +67 -0
- package/protocols/starsiege.js +10 -0
- package/protocols/teamspeak2.js +71 -0
- package/protocols/teamspeak3.js +69 -0
- package/protocols/terraria.js +24 -0
- package/protocols/tribes1.js +153 -0
- package/protocols/tribes1master.js +80 -0
- package/protocols/unreal2.js +150 -0
- package/protocols/ut3.js +45 -0
- package/protocols/valve.js +455 -0
- package/protocols/vcmp.js +10 -0
- package/protocols/ventrilo.js +237 -0
- package/protocols/warsow.js +13 -0
package/bin/gamedig.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import * as process from "node:process";
|
|
4
|
+
|
|
5
|
+
import Minimist from 'minimist'
|
|
6
|
+
import { GameDig } from './../lib/index.js'
|
|
7
|
+
|
|
8
|
+
const argv = Minimist(process.argv.slice(2), {
|
|
9
|
+
boolean: ['pretty', 'debug', 'givenPortOnly', 'requestRules', 'requestRulesRequired', 'requestPlayersRequired'],
|
|
10
|
+
string: ['guildId', 'listenUdpPort', 'ipFamily']
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
const debug = argv.debug
|
|
14
|
+
delete argv.debug
|
|
15
|
+
const pretty = !!argv.pretty || debug
|
|
16
|
+
delete argv.pretty
|
|
17
|
+
const givenPortOnly = argv.givenPortOnly
|
|
18
|
+
delete argv.givenPortOnly
|
|
19
|
+
const requestRulesRequired = argv.requestRulesRequired
|
|
20
|
+
delete argv.requestRulesRequired
|
|
21
|
+
const requestPlayersRequired = argv.requestPlayersRequired
|
|
22
|
+
delete argv.requestPlayersRequired
|
|
23
|
+
|
|
24
|
+
const options = {}
|
|
25
|
+
for (const key of Object.keys(argv)) {
|
|
26
|
+
const value = argv[key]
|
|
27
|
+
|
|
28
|
+
if (key === '_' || key.charAt(0) === '$') { continue }
|
|
29
|
+
|
|
30
|
+
options[key] = value
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (argv._.length >= 1) {
|
|
34
|
+
const target = argv._[0]
|
|
35
|
+
const split = target.split(':')
|
|
36
|
+
options.host = split[0]
|
|
37
|
+
if (split.length >= 2) {
|
|
38
|
+
options.port = split[1]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (debug) {
|
|
42
|
+
options.debug = true
|
|
43
|
+
}
|
|
44
|
+
if (givenPortOnly) {
|
|
45
|
+
options.givenPortOnly = true
|
|
46
|
+
}
|
|
47
|
+
if (requestRulesRequired) {
|
|
48
|
+
options.requestRulesRequired = true
|
|
49
|
+
}
|
|
50
|
+
if (requestPlayersRequired) {
|
|
51
|
+
options.requestPlayersRequired = true
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const printOnPretty = (object) => {
|
|
55
|
+
if (pretty) {
|
|
56
|
+
console.log(JSON.stringify(object, null, ' '))
|
|
57
|
+
} else {
|
|
58
|
+
console.log(JSON.stringify(object))
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const gamedig = new GameDig(options)
|
|
63
|
+
gamedig.query(options)
|
|
64
|
+
.then(printOnPretty)
|
|
65
|
+
.catch((error) => {
|
|
66
|
+
if (debug) {
|
|
67
|
+
if (error instanceof Error) {
|
|
68
|
+
console.log(error.stack)
|
|
69
|
+
} else {
|
|
70
|
+
console.log(error)
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
if (error instanceof Error) {
|
|
74
|
+
error = error.message
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
printOnPretty({ error })
|
|
78
|
+
}
|
|
79
|
+
})
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import dns from 'node:dns'
|
|
2
|
+
import { isIP } from 'node:net'
|
|
3
|
+
import punycode from 'punycode/punycode.js'
|
|
4
|
+
|
|
5
|
+
export default class DnsResolver {
|
|
6
|
+
/**
|
|
7
|
+
* @param {Logger} logger
|
|
8
|
+
*/
|
|
9
|
+
constructor (logger) {
|
|
10
|
+
this.logger = logger
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Resolve a host name to its IP, if the given host name is already
|
|
15
|
+
* an IP address no request is made.
|
|
16
|
+
*
|
|
17
|
+
* If a srvRecordPrefix is provided a SRV request will be made and the
|
|
18
|
+
* port returned will be included in the output.
|
|
19
|
+
* @param {string} host
|
|
20
|
+
* @param {number} ipFamily
|
|
21
|
+
* @param {string=} srvRecordPrefix
|
|
22
|
+
* @returns {Promise<{address:string, port:number=}>}
|
|
23
|
+
*/
|
|
24
|
+
async resolve (host, ipFamily, srvRecordPrefix) {
|
|
25
|
+
this.logger.debug('DNS Lookup: ' + host)
|
|
26
|
+
|
|
27
|
+
// Check if host is IPv4 or IPv6
|
|
28
|
+
if (isIP(host) === 4 || isIP(host) === 6) {
|
|
29
|
+
this.logger.debug('Raw IP Address: ' + host)
|
|
30
|
+
return { address: host }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const asciiForm = punycode.toASCII(host)
|
|
34
|
+
if (asciiForm !== host) {
|
|
35
|
+
this.logger.debug('Encoded punycode: ' + host + ' -> ' + asciiForm)
|
|
36
|
+
host = asciiForm
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (srvRecordPrefix) {
|
|
40
|
+
this.logger.debug('SRV Resolve: ' + srvRecordPrefix + '.' + host)
|
|
41
|
+
let records
|
|
42
|
+
try {
|
|
43
|
+
records = await dns.promises.resolve(srvRecordPrefix + '.' + host, 'SRV')
|
|
44
|
+
if (records.length >= 1) {
|
|
45
|
+
this.logger.debug('Found SRV Records: ', records)
|
|
46
|
+
const record = records[0]
|
|
47
|
+
const srvPort = record.port
|
|
48
|
+
const srvHost = record.name
|
|
49
|
+
if (srvHost === host) {
|
|
50
|
+
throw new Error('Loop in DNS SRV records')
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
port: srvPort,
|
|
54
|
+
...await this.resolve(srvHost, ipFamily, srvRecordPrefix)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
this.logger.debug('No SRV Record')
|
|
58
|
+
} catch (e) {
|
|
59
|
+
this.logger.debug(e)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
this.logger.debug('Standard Resolve: ' + host)
|
|
64
|
+
const dnsResult = await dns.promises.lookup(host, ipFamily)
|
|
65
|
+
// For some reason, this sometimes returns a string address rather than an object.
|
|
66
|
+
// I haven't been able to reproduce, but it's been reported on the issue tracker.
|
|
67
|
+
let address
|
|
68
|
+
if (typeof dnsResult === 'string') {
|
|
69
|
+
address = dnsResult
|
|
70
|
+
} else {
|
|
71
|
+
address = dnsResult.address
|
|
72
|
+
}
|
|
73
|
+
this.logger.debug('Found address: ' + address)
|
|
74
|
+
return { address }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { createSocket } from 'node:dgram'
|
|
2
|
+
import { debugDump } from './HexUtil.js'
|
|
3
|
+
import { promisify } from 'node:util'
|
|
4
|
+
import Logger from './Logger.js'
|
|
5
|
+
|
|
6
|
+
export default class GlobalUdpSocket {
|
|
7
|
+
constructor ({ port }) {
|
|
8
|
+
this.socket = null
|
|
9
|
+
this.callbacks = new Set()
|
|
10
|
+
this.debuggingCallbacks = new Set()
|
|
11
|
+
this.logger = new Logger()
|
|
12
|
+
this.port = port
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async _getSocket () {
|
|
16
|
+
if (!this.socket) {
|
|
17
|
+
const udpSocket = createSocket({
|
|
18
|
+
type: 'udp4',
|
|
19
|
+
reuseAddr: true
|
|
20
|
+
})
|
|
21
|
+
udpSocket.unref()
|
|
22
|
+
udpSocket.on('message', (buffer, rinfo) => {
|
|
23
|
+
const fromAddress = rinfo.address
|
|
24
|
+
const fromPort = rinfo.port
|
|
25
|
+
this.logger.debug(log => {
|
|
26
|
+
log(fromAddress + ':' + fromPort + ' <--UDP(' + this.port + ')')
|
|
27
|
+
log(debugDump(buffer))
|
|
28
|
+
})
|
|
29
|
+
for (const callback of this.callbacks) {
|
|
30
|
+
callback(fromAddress, fromPort, buffer)
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
udpSocket.on('error', e => {
|
|
34
|
+
this.logger.debug('UDP ERROR:', e)
|
|
35
|
+
})
|
|
36
|
+
await promisify(udpSocket.bind).bind(udpSocket)(this.port)
|
|
37
|
+
this.port = udpSocket.address().port
|
|
38
|
+
this.socket = udpSocket
|
|
39
|
+
}
|
|
40
|
+
return this.socket
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async send (buffer, address, port, debug) {
|
|
44
|
+
const socket = await this._getSocket()
|
|
45
|
+
|
|
46
|
+
if (debug) {
|
|
47
|
+
this.logger._print(log => {
|
|
48
|
+
log(address + ':' + port + ' UDP(' + this.port + ')-->')
|
|
49
|
+
log(debugDump(buffer))
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
await promisify(socket.send).bind(socket)(buffer, 0, buffer.length, port, address)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
addCallback (callback, debug) {
|
|
57
|
+
this.callbacks.add(callback)
|
|
58
|
+
if (debug) {
|
|
59
|
+
this.debuggingCallbacks.add(callback)
|
|
60
|
+
this.logger.debugEnabled = true
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
removeCallback (callback) {
|
|
65
|
+
this.callbacks.delete(callback)
|
|
66
|
+
this.debuggingCallbacks.delete(callback)
|
|
67
|
+
this.logger.debugEnabled = this.debuggingCallbacks.size > 0
|
|
68
|
+
}
|
|
69
|
+
}
|
package/lib/HexUtil.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** @param {Buffer} buffer */
|
|
2
|
+
export const debugDump = (buffer) => {
|
|
3
|
+
let hexLine = ''
|
|
4
|
+
let chrLine = ''
|
|
5
|
+
let out = ''
|
|
6
|
+
out += 'Buffer length: ' + buffer.length + ' bytes\n'
|
|
7
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
8
|
+
const sliced = buffer.slice(i, i + 1)
|
|
9
|
+
hexLine += sliced.toString('hex') + ' '
|
|
10
|
+
let chr = sliced.toString()
|
|
11
|
+
if (chr < ' ' || chr > '~') chr = ' '
|
|
12
|
+
chrLine += chr + ' '
|
|
13
|
+
if (hexLine.length > 60 || i === buffer.length - 1) {
|
|
14
|
+
out += hexLine + '\n'
|
|
15
|
+
out += chrLine + '\n'
|
|
16
|
+
hexLine = chrLine = ''
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return out
|
|
20
|
+
}
|
package/lib/Logger.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { debugDump } from './HexUtil.js'
|
|
2
|
+
import { Buffer} from 'node:buffer'
|
|
3
|
+
|
|
4
|
+
export default class Logger {
|
|
5
|
+
constructor () {
|
|
6
|
+
this.debugEnabled = false
|
|
7
|
+
this.prefix = ''
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
debug (...args) {
|
|
11
|
+
if (!this.debugEnabled) return
|
|
12
|
+
this._print(...args)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
_print (...args) {
|
|
16
|
+
try {
|
|
17
|
+
const strings = this._convertArgsToStrings(...args)
|
|
18
|
+
if (strings.length) {
|
|
19
|
+
if (this.prefix) {
|
|
20
|
+
strings.unshift(this.prefix)
|
|
21
|
+
}
|
|
22
|
+
console.log(...strings)
|
|
23
|
+
}
|
|
24
|
+
} catch (e) {
|
|
25
|
+
console.log('Error while logging: ' + e)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_convertArgsToStrings (...args) {
|
|
30
|
+
const out = []
|
|
31
|
+
for (const arg of args) {
|
|
32
|
+
if (arg instanceof Error) {
|
|
33
|
+
out.push(arg.stack)
|
|
34
|
+
} else if (arg instanceof Buffer) {
|
|
35
|
+
out.push(debugDump(arg))
|
|
36
|
+
} else if (typeof arg === 'function') {
|
|
37
|
+
const result = arg.call(undefined, (...args) => this._print(...args))
|
|
38
|
+
if (result !== undefined) out.push(...this._convertArgsToStrings(result))
|
|
39
|
+
} else {
|
|
40
|
+
out.push(arg)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return out
|
|
44
|
+
}
|
|
45
|
+
}
|
package/lib/Promises.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export default class Promises {
|
|
2
|
+
static createTimeout (timeoutMs, timeoutMsg) {
|
|
3
|
+
let cancel = null
|
|
4
|
+
const wrapped = new Promise((resolve, reject) => {
|
|
5
|
+
const timeout = setTimeout(
|
|
6
|
+
() => {
|
|
7
|
+
reject(new Error(timeoutMsg + ' - Timed out after ' + timeoutMs + 'ms'))
|
|
8
|
+
},
|
|
9
|
+
timeoutMs
|
|
10
|
+
)
|
|
11
|
+
cancel = () => {
|
|
12
|
+
clearTimeout(timeout)
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
wrapped.cancel = cancel
|
|
16
|
+
return wrapped
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { lookup } from './game-resolver.js'
|
|
2
|
+
import { getProtocol } from './ProtocolResolver.js'
|
|
3
|
+
import GlobalUdpSocket from './GlobalUdpSocket.js'
|
|
4
|
+
|
|
5
|
+
const defaultOptions = {
|
|
6
|
+
socketTimeout: 2000,
|
|
7
|
+
attemptTimeout: 10000,
|
|
8
|
+
maxAttempts: 1,
|
|
9
|
+
ipFamily: 0
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default class QueryRunner {
|
|
13
|
+
constructor (runnerOpts = {}) {
|
|
14
|
+
this.udpSocket = new GlobalUdpSocket({
|
|
15
|
+
port: runnerOpts.listenUdpPort
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async run (userOptions) {
|
|
20
|
+
for (const key of Object.keys(userOptions)) {
|
|
21
|
+
const value = userOptions[key]
|
|
22
|
+
if (['port', 'ipFamily'].includes(key)) {
|
|
23
|
+
userOptions[key] = parseInt(value)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const {
|
|
28
|
+
port_query: gameQueryPort,
|
|
29
|
+
port_query_offset: gameQueryPortOffset,
|
|
30
|
+
...gameOptions
|
|
31
|
+
} = lookup(userOptions.type)
|
|
32
|
+
const attempts = []
|
|
33
|
+
|
|
34
|
+
const optionsCollection = {
|
|
35
|
+
...defaultOptions,
|
|
36
|
+
...gameOptions,
|
|
37
|
+
...userOptions
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const addAttemptWithPort = port => {
|
|
41
|
+
attempts.push({
|
|
42
|
+
...optionsCollection,
|
|
43
|
+
port
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (userOptions.port) {
|
|
48
|
+
if (!userOptions.givenPortOnly) {
|
|
49
|
+
if (gameQueryPortOffset) { addAttemptWithPort(userOptions.port + gameQueryPortOffset) }
|
|
50
|
+
|
|
51
|
+
if (userOptions.port === gameOptions.port && gameQueryPort) { addAttemptWithPort(gameQueryPort) }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
attempts.push(optionsCollection)
|
|
55
|
+
} else if (gameQueryPort) {
|
|
56
|
+
addAttemptWithPort(gameQueryPort)
|
|
57
|
+
} else if (gameOptions.port) {
|
|
58
|
+
addAttemptWithPort(gameOptions.port + (gameQueryPortOffset || 0))
|
|
59
|
+
} else {
|
|
60
|
+
// Hopefully the request doesn't need a port. If it does, it'll fail when making the request.
|
|
61
|
+
attempts.push(optionsCollection)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const numRetries = userOptions.maxAttempts || gameOptions.maxAttempts || defaultOptions.maxAttempts
|
|
65
|
+
|
|
66
|
+
let attemptNum = 0
|
|
67
|
+
const errors = []
|
|
68
|
+
for (const attempt of attempts) {
|
|
69
|
+
for (let retry = 0; retry < numRetries; retry++) {
|
|
70
|
+
attemptNum++
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
return await this._attempt(attempt)
|
|
74
|
+
} catch (e) {
|
|
75
|
+
e.stack = 'Attempt #' + attemptNum + ' - Port=' + attempt.port + ' Retry=' + (retry) + ':\n' + e.stack
|
|
76
|
+
errors.push(e)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const err = new Error('Failed all ' + errors.length + ' attempts')
|
|
82
|
+
for (const e of errors) {
|
|
83
|
+
err.stack += '\n' + e.stack
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
throw err
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async _attempt (options) {
|
|
90
|
+
const core = getProtocol(options.protocol)
|
|
91
|
+
core.options = options
|
|
92
|
+
core.udpSocket = this.udpSocket
|
|
93
|
+
return await core.runOnceSafe()
|
|
94
|
+
}
|
|
95
|
+
}
|
package/lib/Results.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export class Player {
|
|
2
|
+
name = ''
|
|
3
|
+
raw = {}
|
|
4
|
+
|
|
5
|
+
constructor (data) {
|
|
6
|
+
if (typeof data === 'string') {
|
|
7
|
+
this.name = data
|
|
8
|
+
} else {
|
|
9
|
+
const { name, ...raw } = data
|
|
10
|
+
if (name) this.name = name
|
|
11
|
+
if (raw) this.raw = raw
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class Players extends Array {
|
|
17
|
+
push (data) {
|
|
18
|
+
super.push(new Player(data))
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class Results {
|
|
23
|
+
name = ''
|
|
24
|
+
map = ''
|
|
25
|
+
password = false
|
|
26
|
+
|
|
27
|
+
raw = {}
|
|
28
|
+
|
|
29
|
+
maxplayers = 0
|
|
30
|
+
players = new Players()
|
|
31
|
+
bots = new Players()
|
|
32
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { games } from './games.js'
|
|
2
|
+
|
|
3
|
+
export const lookup = (type) => {
|
|
4
|
+
if (!type) { throw Error('No game specified') }
|
|
5
|
+
|
|
6
|
+
if (type.startsWith('protocol-')) {
|
|
7
|
+
return {
|
|
8
|
+
protocol: type.substring(9)
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const game = games[type]
|
|
13
|
+
|
|
14
|
+
if (!game) { throw Error('Invalid game: ' + type) }
|
|
15
|
+
|
|
16
|
+
return game.options
|
|
17
|
+
}
|
package/lib/gamedig.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import QueryRunner from './QueryRunner.js'
|
|
2
|
+
|
|
3
|
+
let singleton = null
|
|
4
|
+
|
|
5
|
+
export class GameDig {
|
|
6
|
+
constructor (runnerOpts) {
|
|
7
|
+
this.queryRunner = new QueryRunner(runnerOpts)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async query (userOptions) {
|
|
11
|
+
return await this.queryRunner.run(userOptions)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static getInstance () {
|
|
15
|
+
if (!singleton) { singleton = new GameDig() }
|
|
16
|
+
|
|
17
|
+
return singleton
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static async query (...args) {
|
|
21
|
+
return await GameDig.getInstance().query(...args)
|
|
22
|
+
}
|
|
23
|
+
}
|