Merge remote-tracking branch 'upstream/master' into RCON-PacketParser

# Conflicts:
#	core/rcon.js
This commit is contained in:
Skillet 2023-12-28 18:53:20 -05:00
commit a1ea6d10d1
15 changed files with 69 additions and 16 deletions

View File

@ -210,7 +210,7 @@ Interested in creating your own plugin? [See more here](./squad-server/plugins/r
<h6>Description</h6> <h6>Description</h6>
<p>Message SquadJS will send to players warning them they will be kicked</p> <p>Message SquadJS will send to players warning them they will be kicked</p>
<h6>Default</h6> <h6>Default</h6>
<pre><code>Join a squad, you are are unassigned and will be kicked</code></pre></li> <pre><code>Join a squad, you are unassigned and will be kicked</code></pre></li>
<li><h4>kickMessage</h4> <li><h4>kickMessage</h4>
<h6>Description</h6> <h6>Description</h6>
<p>Message to send to players when they are kicked</p> <p>Message to send to players when they are kicked</p>

View File

@ -43,7 +43,7 @@
{ {
"plugin": "AutoKickUnassigned", "plugin": "AutoKickUnassigned",
"enabled": true, "enabled": true,
"warningMessage": "Join a squad, you are are unassigned and will be kicked", "warningMessage": "Join a squad, you are unassigned and will be kicked",
"kickMessage": "Unassigned - automatically removed", "kickMessage": "Unassigned - automatically removed",
"frequencyOfWarnings": 30, "frequencyOfWarnings": 30,
"unassignedTimer": 360, "unassignedTimer": 360,

View File

@ -4,6 +4,7 @@ class Logger {
constructor() { constructor() {
this.verboseness = {}; this.verboseness = {};
this.colors = {}; this.colors = {};
this.includeTimestamps = false;
} }
verbose(module, verboseness, message, ...extras) { verbose(module, verboseness, message, ...extras) {
@ -11,7 +12,12 @@ class Logger {
if (typeof colorFunc !== 'function') colorFunc = chalk.white; if (typeof colorFunc !== 'function') colorFunc = chalk.white;
if ((this.verboseness[module] || 1) >= verboseness) if ((this.verboseness[module] || 1) >= verboseness)
console.log(`[${colorFunc(module)}][${verboseness}] ${message}`, ...extras); console.log(
`${this.includeTimestamps ? '[' + new Date().toISOString() + ']' : ''}[${colorFunc(
module
)}][${verboseness}] ${message}`,
...extras
);
} }
setVerboseness(module, verboseness) { setVerboseness(module, verboseness) {
@ -21,6 +27,10 @@ class Logger {
setColor(module, color) { setColor(module, color) {
this.colors[module] = color; this.colors[module] = color;
} }
setTimeStamps(option) {
this.includeTimestamps = option;
}
} }
export default new Logger(); export default new Logger();

View File

@ -337,6 +337,8 @@ export default class Rcon extends EventEmitter {
if (type === SERVERDATA_AUTH) { if (type === SERVERDATA_AUTH) {
this.callbackIds.push({ id: this.count, cmd: body }); this.callbackIds.push({ id: this.count, cmd: body });
Logger.verbose('RCON', 2, `Writing Auth Packet`);
Logger.verbose('RCON', 4, `Writing packet with type "${type}" and body "${body}".`);
this.responseCallbackQueue.push(() => {}); this.responseCallbackQueue.push(() => {});
this.responseCallbackQueue.push((decodedPacket) => { this.responseCallbackQueue.push((decodedPacket) => {
this.client.removeListener('error', onError); this.client.removeListener('error', onError);
@ -350,6 +352,7 @@ export default class Rcon extends EventEmitter {
} }
}); });
} else { } else {
Logger.verbose('RCON', 2, `Writing packet with type "${type}" and body "${body}".`);
this.callbackIds.push({ id: this.count, cmd: body }); this.callbackIds.push({ id: this.count, cmd: body });
this.responseCallbackQueue.push((response) => { this.responseCallbackQueue.push((response) => {
this.client.removeListener('error', onError); this.client.removeListener('error', onError);

View File

@ -1,6 +1,6 @@
{ {
"name": "SquadJS", "name": "SquadJS",
"version": "3.6.1", "version": "3.8.2",
"repository": "https://github.com/Team-Silver-Sphere/SquadJS.git", "repository": "https://github.com/Team-Silver-Sphere/SquadJS.git",
"author": "Thomas Smyth <https://github.com/Thomas-Smyth>", "author": "Thomas Smyth <https://github.com/Thomas-Smyth>",
"license": "BSL-1.0", "license": "BSL-1.0",

View File

@ -17,6 +17,8 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
export default class SquadServerFactory { export default class SquadServerFactory {
static async buildFromConfig(config) { static async buildFromConfig(config) {
Logger.setTimeStamps(config.logger.timestamps ? config.logger.timestamps : false);
const plugins = await Plugins.getPlugins(); const plugins = await Plugins.getPlugins();
for (const plugin of Object.keys(plugins)) { for (const plugin of Object.keys(plugins)) {

View File

@ -242,6 +242,8 @@ export default class SquadServer extends EventEmitter {
this.logParser.on('PLAYER_WOUNDED', async (data) => { this.logParser.on('PLAYER_WOUNDED', async (data) => {
data.victim = await this.getPlayerByName(data.victimName); data.victim = await this.getPlayerByName(data.victimName);
data.attacker = await this.getPlayerByName(data.attackerName); data.attacker = await this.getPlayerByName(data.attackerName);
if (!data.attacker)
data.attacker = await this.getPlayerByController(data.attackerPlayerController);
if (data.victim && data.attacker) if (data.victim && data.attacker)
data.teamkill = data.teamkill =
@ -257,6 +259,9 @@ export default class SquadServer extends EventEmitter {
this.logParser.on('PLAYER_DIED', async (data) => { this.logParser.on('PLAYER_DIED', async (data) => {
data.victim = await this.getPlayerByName(data.victimName); data.victim = await this.getPlayerByName(data.victimName);
data.attacker = await this.getPlayerByName(data.attackerName);
if (!data.attacker)
data.attacker = await this.getPlayerByController(data.attackerPlayerController);
if (data.victim && data.attacker) if (data.victim && data.attacker)
data.teamkill = data.teamkill =
@ -351,6 +356,9 @@ export default class SquadServer extends EventEmitter {
players.push({ players.push({
...oldPlayerInfo[player.steamID], ...oldPlayerInfo[player.steamID],
...player, ...player,
playercontroller: this.logParser.eventStore.players[player.steamID]
? this.logParser.eventStore.players[player.steamID].controller
: null,
squad: await this.getSquadByID(player.teamID, player.squadID) squad: await this.getSquadByID(player.teamID, player.squadID)
}); });
@ -542,6 +550,13 @@ export default class SquadServer extends EventEmitter {
return this.getPlayerByCondition((player) => player.suffix === suffix, forceUpdate, false); return this.getPlayerByCondition((player) => player.suffix === suffix, forceUpdate, false);
} }
async getPlayerByController(controller, forceUpdate) {
return this.getPlayerByCondition(
(player) => player.playercontroller === controller,
forceUpdate
);
}
async pingSquadJSAPI() { async pingSquadJSAPI() {
if (this.pingSquadJSAPITimeout) clearTimeout(this.pingSquadJSAPITimeout); if (this.pingSquadJSAPITimeout) clearTimeout(this.pingSquadJSAPITimeout);

View File

@ -31,7 +31,7 @@ export default class Layer {
respawnDelay: vehicle.respawnTime respawnDelay: vehicle.respawnTime
})), })),
numberOfTanks: (data[t].vehicles || []).filter((v) => { numberOfTanks: (data[t].vehicles || []).filter((v) => {
return v.icon.match(/tank/); return v.icon.match(/_tank/);
}).length, }).length,
numberOfHelicopters: (data[t].vehicles || []).filter((v) => { numberOfHelicopters: (data[t].vehicles || []).filter((v) => {
return v.icon.match(/helo/); return v.icon.match(/helo/);

View File

@ -22,7 +22,7 @@ class Layers {
Logger.verbose('Layers', 1, 'Pulling layers...'); Logger.verbose('Layers', 1, 'Pulling layers...');
const response = await axios.get( const response = await axios.get(
'https://raw.githubusercontent.com/Squad-Wiki-Editorial/squad-wiki-pipeline-map-data/master/completed_output/_Current%20Version/finished.json' 'https://raw.githubusercontent.com/Squad-Wiki/squad-wiki-pipeline-map-data/master/completed_output/_Current%20Version/finished.json'
); );
for (const layer of response.data.Maps) { for (const layer of response.data.Maps) {

View File

@ -1,6 +1,6 @@
export default { export default {
regex: regex:
/^\[([0-9.:-]+)]\[([ 0-9]*)]LogNet: UNetConnection::Close: \[UNetConnection\] RemoteAddr: ([0-9]{17}):[0-9]+, Name: SteamNetConnection_[0-9]+, Driver: GameNetDriver SteamNetDriver_[0-9]+, IsServer: YES, PC: (BP_PlayerController_C_[0-9]+), Owner: BP_PlayerController_C_[0-9]+, UniqueId: Steam:UNKNOWN \[.*\], Channels: [0-9]+, Time: [0-9.:-]+/, /^\[([0-9.:-]+)]\[([ 0-9]*)]LogNet: UChannel::Close: Sending CloseBunch\. ChIndex == [0-9]+\. Name: \[UChannel\] ChIndex: [0-9]+, Closing: [0-9]+ \[UNetConnection\] RemoteAddr: ([0-9]{17}):[0-9]+, Name: SteamNetConnection_[0-9]+, Driver: GameNetDriver SteamNetDriver_[0-9]+, IsServer: YES, PC: ([^ ]+PlayerController_C_[0-9]+), Owner: [^ ]+PlayerController_C_[0-9]+/,
onMatch: (args, logParser) => { onMatch: (args, logParser) => {
const data = { const data = {
raw: args[0], raw: args[0],

View File

@ -7,7 +7,8 @@ export default {
time: args[1], time: args[1],
chainID: args[2], chainID: args[2],
playerSuffix: args[3], playerSuffix: args[3],
possessClassname: args[4] possessClassname: args[4],
pawn: args[5]
}; };
logParser.eventStore.session[args[3]] = args[2]; logParser.eventStore.session[args[3]] = args[2];

View File

@ -15,9 +15,9 @@
"pg": "^8.5.1", "pg": "^8.5.1",
"pg-hstore": "^2.3.3", "pg-hstore": "^2.3.3",
"sequelize": "^6.3.5", "sequelize": "^6.3.5",
"socket.io": "^3.1.2", "socket.io": "^4.5.4",
"sqlite3": "^5.0.0", "sqlite3": "^5.0.0",
"tedious": "^9.2.1", "tedious": "^15.1.2",
"tinygradient": "^1.1.2" "tinygradient": "^1.1.2"
}, },
"exports": { "exports": {

View File

@ -17,7 +17,7 @@ export default class AutoKickUnassigned extends BasePlugin {
warningMessage: { warningMessage: {
required: false, required: false,
description: 'Message SquadJS will send to players warning them they will be kicked', description: 'Message SquadJS will send to players warning them they will be kicked',
default: 'Join a squad, you are are unassigned and will be kicked' default: 'Join a squad, you are unassigned and will be kicked'
}, },
kickMessage: { kickMessage: {
required: false, required: false,

View File

@ -15,10 +15,24 @@ export default class DiscordBasePlugin extends BasePlugin {
} }
async prepareToMount() { async prepareToMount() {
try {
this.channel = await this.options.discordClient.channels.fetch(this.options.channelID); this.channel = await this.options.discordClient.channels.fetch(this.options.channelID);
} catch (error) {
this.channel = null;
this.verbose(
1,
`Could not fetch Discord channel with channelID "${this.options.channelID}". Error: ${error.message}`
);
this.verbose(2, `${error.stack}`);
}
} }
async sendDiscordMessage(message) { async sendDiscordMessage(message) {
if (!this.channel) {
this.verbose(1, `Could not send Discord Message. Channel not initialized.`);
return;
}
if (typeof message === 'object' && 'embed' in message) if (typeof message === 'object' && 'embed' in message)
message.embed.footer = message.embed.footer || { text: COPYRIGHT_MESSAGE }; message.embed.footer = message.embed.footer || { text: COPYRIGHT_MESSAGE };

View File

@ -139,9 +139,11 @@ export default class SquadRcon extends Rcon {
const players = []; const players = [];
if (!response || response.length < 1) return players;
for (const line of response.split('\n')) { for (const line of response.split('\n')) {
const match = line.match( const match = line.match(
/ID: ([0-9]+) \| SteamID: ([0-9]{17}) \| Name: (.+) \| Team ID: ([0-9]+) \| Squad ID: ([0-9]+|N\/A)/ /ID: ([0-9]+) \| SteamID: ([0-9]{17}) \| Name: (.+) \| Team ID: ([0-9]+) \| Squad ID: ([0-9]+|N\/A) \| Is Leader: (True|False) \| Role: ([A-Za-z0-9_]*)\b/
); );
if (!match) continue; if (!match) continue;
@ -150,7 +152,9 @@ export default class SquadRcon extends Rcon {
steamID: match[2], steamID: match[2],
name: match[3], name: match[3],
teamID: match[4], teamID: match[4],
squadID: match[5] !== 'N/A' ? match[5] : null squadID: match[5] !== 'N/A' ? match[5] : null,
isLeader: match[6] === 'True',
role: match[7]
}); });
} }
@ -164,9 +168,11 @@ export default class SquadRcon extends Rcon {
let teamName; let teamName;
let teamID; let teamID;
if (!responseSquad || responseSquad.length < 1) return squads;
for (const line of responseSquad.split('\n')) { for (const line of responseSquad.split('\n')) {
const match = line.match( const match = line.match(
/ID: ([0-9]+) \| Name: (.+) \| Size: ([0-9]+) \| Locked: (True|False)/ /ID: ([0-9]+) \| Name: (.+) \| Size: ([0-9]+) \| Locked: (True|False) \| Creator Name: (.+) \| Creator Steam ID: ([0-9]{17})/
); );
const matchSide = line.match(/Team ID: (1|2) \((.+)\)/); const matchSide = line.match(/Team ID: (1|2) \((.+)\)/);
if (matchSide) { if (matchSide) {
@ -174,11 +180,13 @@ export default class SquadRcon extends Rcon {
teamName = matchSide[2]; teamName = matchSide[2];
} }
if (!match) continue; if (!match) continue;
await squads.push({ squads.push({
squadID: match[1], squadID: match[1],
squadName: match[2], squadName: match[2],
size: match[3], size: match[3],
locked: match[4], locked: match[4],
creatorName: match[5],
creatorSteamID: match[6],
teamID: teamID, teamID: teamID,
teamName: teamName teamName: teamName
}); });