The code imports various modules and defines two asynchronous functions, getServerChannel
and updateChannelThread
, which interact with the Discord API to fetch and manipulate channels and threads in a Discord server. The getServerChannel
function finds a suitable channel based on a server's gametype and settings, while the updateChannelThread
function updates an existing thread or creates a new one if it doesn't exist.
npm run import -- "monitor q3 servers"
var importer = require('../Core')
var serverApi = importer.import("quake 3 server commands")
var {authorizeGateway} = importer.import("authorize discord")
var discordApi = importer.import("discord api")
var removeCtrlChars = importer.import("remove ctrl characters")
var DEFAULT_USERNAME = 'Orbb'
async function getServerChannel(server) {
// get a list of channels to pair gametype up with
var channels = await discordApi.guildChannels()
var channel
// sort ffa/ctf/freeZe
if(!channel && (server.server_freezetag == '1'
|| server.gamename.toLowerCase() == 'freon'
|| (typeof server.xp_version != 'undefined'
&& server.g_gametype == '8'))) {
channel = channels.filter(c => c.name.toLowerCase() == 'freeze-tag')[0]
}
if(!channel && server.gamename.toLowerCase() == 'defrag') {
channel = channels.filter(c => c.name.toLowerCase() == 'defrag')[0]
}
if(!channel && server.g_gametype == '4') {
channel = channels.filter(c => c.name.toLowerCase() == 'capture-the-flag')[0]
}
if(!channel && server.g_gametype == '3') {
channel = channels.filter(c => c.name.toLowerCase() == 'team-deathmatch')[0]
}
if(!channel && typeof server.xp_version != 'undefined'
&& server.g_gametype == '7') {
channel = channels.filter(c => c.name.toLowerCase() == 'clan-arena')[0]
}
if(!channel && typeof server.xp_version != 'undefined'
&& server.g_gametype == '1') {
channel = channels.filter(c => c.name.toLowerCase() == '1on1-duel')[0]
}
if(!channel) {
channel = channels.filter(c => c.name.toLowerCase() == 'general')[0]
}
return channel
}
async function updateChannelThread(threadName, channel, json) {
// find old threads to reactivate
var archived = (await discordApi.archivedThreads(channel.id)).threads
.filter(t => t.name == threadName)
var thread
var removeOld
if(archived.length > 0) {
thread = archived[0]
removeOld = (await discordApi.getPins(thread.id))
.filter(p => p.author.username == DEFAULT_USERNAME)
} else {
// thread is already active
var active = (await discordApi.activeThreads(channel.id)).threads
.filter(t => t.name == threadName)
if(active.length > 0) {
// find and update previous "whos online" message, pins?
thread = active[0]
var pins = (await discordApi.getPins(thread.id))
.filter(p => p.author.username == DEFAULT_USERNAME)
if(pins.length > 0) {
await discordApi.updateMessage(json, pins[0].id, thread.id)
return thread
}
} else {
thread = await discordApi.createThread(threadName, channel.id)
}
}
// create new "whos online message"
var message = await discordApi.createMessage(json, thread.id)
await discordApi.pinMessage(message.id, thread.id)
if(removeOld && removeOld.length > 0) {
await discordApi.unpinMessage(removeOld[0].id, thread.id)
}
return thread
}
async function monitorServer(address = 'q3msk.ru', port = 27977) {
await serverApi.getInfo(address, port)
await serverApi.getStatus(address, port)
var server = await serverApi.nextStatusResponse(address, port)
if(!server || server.monitorRunning)
return
server.monitorRunning = true
var threadName = 'Pickup for ' + removeCtrlChars(server.sv_hostname || server.hostname).replace(/[^0-9a-z-]/ig, '-')
console.log(threadName)
var redTeam = (server.Players_Red || '').trim()
.split(/\s+/ig).filter(n => n)
.map(i => parseInt(i))
var blueTeam = (server.Players_Blue || '').trim()
.split(/\s+/ig).filter(n => n)
.map(i => parseInt(i))
server.players.forEach(p => {
if(redTeam.includes(p.i))
p.team = 'red'
else if (blueTeam.includes(p.i))
p.team = 'blue'
else
p.team = 'other'
})
server.players.sort((a, b) => {
return a.team - b.team
})
var json
if(redTeam.length > 0 || blueTeam.length > 0) {
json = {
embeds: [{
title: removeCtrlChars(server.sv_hostname || server.hostname || server.gamename || server.game || ''),
description: server.ip + ':' + server.port,
color: 0xdda60f,
fields: [
{
name: 'Map',
value: server.mapname,
inline: false
},
{
name: 'Players',
value: server.players.length + '/' + server.sv_maxclients,
inline: false
},
{
name: 'Player',
value: ':red_circle: Red Team\n```http\n'
+ server.players.filter(p => p.team == 'red').map((p, i) => (p.i) + ') '
+ removeCtrlChars(p.name)).join('\n') + '\u0020\n```\n'
+ ':blue_circle: Blue Team\n```http\n'
+ server.players.filter(p => p.team == 'blue').map((p, i) => (p.i) + ') '
+ removeCtrlChars(p.name)).join('\n') + '\u0020\n```\n'
+ 'Other\n```http\n'
+ server.players.filter(p => p.team == 'other').map((p, i) => (p.i) + ') '
+ removeCtrlChars(p.name)).join('\n') + '\u0020\n```\n',
inline: true
},
{
name: 'Score',
value: '-\n```yaml\n' + server.players.filter(p => p.team == 'red').map(p => p.score).join('\n') + '\u0020\n```'
+ '-\n```yaml\n' + server.players.filter(p => p.team == 'blue').map(p => p.score).join('\n') + '\u0020\n```'
+ '-\n```yaml\n' + server.players.filter(p => p.team == 'other').map(p => p.score).join('\n') + '\u0020\n```',
inline: true
},
{
name: 'Ping',
value: '-\n```fix\n' + server.players.filter(p => p.team == 'red').map(p => p.ping).join('\n') + '\u0020\n```'
+ '-\n```fix\n' + server.players.filter(p => p.team == 'blue').map(p => p.ping).join('\n') + '\u0020\n```'
+ '-\n```fix\n' + server.players.filter(p => p.team == 'other').map(p => p.ping).join('\n') + '\u0020\n```',
inline: true
}
]
}]
}
} else {
json = {
embeds: [{
title: removeCtrlChars(server.sv_hostname || server.hostname || server.gamename || server.game || ''),
description: server.ip + ':' + server.port,
color: 0xdda60f,
fields: [
{
name: 'Map',
value: server.mapname,
inline: false
},
{
name: 'Players',
value: server.players.length + '/' + server.sv_maxclients,
inline: false
},
{
name: 'Player',
value: '```http\n' + server.players.map((p, i) => (p.i) + ') '
+ removeCtrlChars(p.name)).join('\n') + '\u0020\n```',
inline: true
},
{
name: 'Score',
value: '```yaml\n' + server.players.map(p => p.score).join('\n') + '\u0020\n```',
inline: true
},
{
name: 'Ping',
value: '```fix\n' + server.players.map(p => p.ping).join('\n') + '\u0020\n```',
inline: true
}
]
}]
}
}
// TODO: comment this line out when launched from index? monitor script
await authorizeGateway()
var channel = getServerChannel(server)
var thread
if(!channel) {
console.log('No channel to create thread on.')
} else {
thread = await updateChannelThread(threadName, channel, json)
server.channelId = thread.id
}
server.monitorRunning = setTimeout(() => {
monitorServer(address, port)
}, 60 * 1000)
return thread
}
module.exports = monitorServer
const { serverApi, authorizeGateway, discordApi, removeCtrlChars } = require('../Core');
const DEFAULT_USERNAME = 'Orbb';
Code Breakdown
The code starts by importing various modules using require()
and import()
:
var importer = require('../Core')
var serverApi = importer.import('quake 3 server commands')
var {authorizeGateway} = importer.import('authorize discord')
var discordApi = importer.import('discord api')
var removeCtrlChars = importer.import('remove ctrl characters')
var DEFAULT_USERNAME = 'Orbb'
getServerChannel
FunctionThe getServerChannel
function is an asynchronous function that takes a server
object as an argument. Its purpose is to find a suitable Discord channel based on the server's gametype and settings.
async function getServerChannel(server) {
//...
}
Here's a high-level overview of the function:
discordApi.guildChannels()
.updateChannelThread
FunctionThe updateChannelThread
function is another asynchronous function that takes three arguments: threadName
, channel
, and json
. Its purpose is to update an existing thread in the Discord channel.
async function updateChannelThread(threadName, channel, json) {
//...
}
Here's a high-level overview of the function:
discordApi.archivedThreads()
.threadName
exists in the archived threads.The code uses various Discord API functions, such as guildChannels()
, archivedThreads()
, and reactivateThread()
. These functions are not defined in the provided code snippet, so it's assumed that they are part of the discordApi
module.