diff --git a/README.md b/README.md
index e1b720e34..b137e4f9f 100644
--- a/README.md
+++ b/README.md
@@ -210,7 +210,7 @@ Interested in creating your own plugin? [See more here](./squad-server/plugins/r
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
+ Join a squad, you are unassigned and will be kicked
kickMessage
Description
Message to send to players when they are kicked
diff --git a/config.json b/config.json
index e68f5e58f..c3e82bc6a 100644
--- a/config.json
+++ b/config.json
@@ -43,7 +43,7 @@
{
"plugin": "AutoKickUnassigned",
"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",
"frequencyOfWarnings": 30,
"unassignedTimer": 360,
diff --git a/core/logger.js b/core/logger.js
index b20ddbe1d..564cf208a 100644
--- a/core/logger.js
+++ b/core/logger.js
@@ -4,6 +4,7 @@ class Logger {
constructor() {
this.verboseness = {};
this.colors = {};
+ this.includeTimestamps = false;
}
verbose(module, verboseness, message, ...extras) {
@@ -11,7 +12,12 @@ class Logger {
if (typeof colorFunc !== 'function') colorFunc = chalk.white;
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) {
@@ -21,6 +27,10 @@ class Logger {
setColor(module, color) {
this.colors[module] = color;
}
+
+ setTimeStamps(option) {
+ this.includeTimestamps = option;
+ }
}
export default new Logger();
diff --git a/core/rcon.js b/core/rcon.js
index af6b8997b..604cbf228 100644
--- a/core/rcon.js
+++ b/core/rcon.js
@@ -337,6 +337,8 @@ export default class Rcon extends EventEmitter {
if (type === SERVERDATA_AUTH) {
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((decodedPacket) => {
this.client.removeListener('error', onError);
@@ -350,6 +352,7 @@ export default class Rcon extends EventEmitter {
}
});
} else {
+ Logger.verbose('RCON', 2, `Writing packet with type "${type}" and body "${body}".`);
this.callbackIds.push({ id: this.count, cmd: body });
this.responseCallbackQueue.push((response) => {
this.client.removeListener('error', onError);
diff --git a/package.json b/package.json
index f614ed00e..29459d4ec 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "SquadJS",
- "version": "3.6.1",
+ "version": "3.8.2",
"repository": "https://github.com/Team-Silver-Sphere/SquadJS.git",
"author": "Thomas Smyth ",
"license": "BSL-1.0",
diff --git a/squad-server/factory.js b/squad-server/factory.js
index df91aa1ba..a8865a5a9 100644
--- a/squad-server/factory.js
+++ b/squad-server/factory.js
@@ -17,6 +17,8 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
export default class SquadServerFactory {
static async buildFromConfig(config) {
+ Logger.setTimeStamps(config.logger.timestamps ? config.logger.timestamps : false);
+
const plugins = await Plugins.getPlugins();
for (const plugin of Object.keys(plugins)) {
diff --git a/squad-server/index.js b/squad-server/index.js
index 5aa1bf580..490f0a7da 100644
--- a/squad-server/index.js
+++ b/squad-server/index.js
@@ -242,6 +242,8 @@ export default class SquadServer extends EventEmitter {
this.logParser.on('PLAYER_WOUNDED', async (data) => {
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)
data.teamkill =
@@ -257,6 +259,9 @@ export default class SquadServer extends EventEmitter {
this.logParser.on('PLAYER_DIED', async (data) => {
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)
data.teamkill =
@@ -351,6 +356,9 @@ export default class SquadServer extends EventEmitter {
players.push({
...oldPlayerInfo[player.steamID],
...player,
+ playercontroller: this.logParser.eventStore.players[player.steamID]
+ ? this.logParser.eventStore.players[player.steamID].controller
+ : null,
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);
}
+ async getPlayerByController(controller, forceUpdate) {
+ return this.getPlayerByCondition(
+ (player) => player.playercontroller === controller,
+ forceUpdate
+ );
+ }
+
async pingSquadJSAPI() {
if (this.pingSquadJSAPITimeout) clearTimeout(this.pingSquadJSAPITimeout);
diff --git a/squad-server/layers/layer.js b/squad-server/layers/layer.js
index e19fd30b9..78bb0b08d 100644
--- a/squad-server/layers/layer.js
+++ b/squad-server/layers/layer.js
@@ -31,7 +31,7 @@ export default class Layer {
respawnDelay: vehicle.respawnTime
})),
numberOfTanks: (data[t].vehicles || []).filter((v) => {
- return v.icon.match(/tank/);
+ return v.icon.match(/_tank/);
}).length,
numberOfHelicopters: (data[t].vehicles || []).filter((v) => {
return v.icon.match(/helo/);
diff --git a/squad-server/layers/layers.js b/squad-server/layers/layers.js
index 70207416a..b2cc4daae 100644
--- a/squad-server/layers/layers.js
+++ b/squad-server/layers/layers.js
@@ -22,7 +22,7 @@ class Layers {
Logger.verbose('Layers', 1, 'Pulling layers...');
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) {
diff --git a/squad-server/log-parser/player-disconnected.js b/squad-server/log-parser/player-disconnected.js
index 6df5e6436..352a01248 100644
--- a/squad-server/log-parser/player-disconnected.js
+++ b/squad-server/log-parser/player-disconnected.js
@@ -1,6 +1,6 @@
export default {
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) => {
const data = {
raw: args[0],
diff --git a/squad-server/log-parser/player-possess.js b/squad-server/log-parser/player-possess.js
index 68dda7031..12ceb84c6 100644
--- a/squad-server/log-parser/player-possess.js
+++ b/squad-server/log-parser/player-possess.js
@@ -7,7 +7,8 @@ export default {
time: args[1],
chainID: args[2],
playerSuffix: args[3],
- possessClassname: args[4]
+ possessClassname: args[4],
+ pawn: args[5]
};
logParser.eventStore.session[args[3]] = args[2];
diff --git a/squad-server/package.json b/squad-server/package.json
index 8e63448ce..c7d8104c2 100644
--- a/squad-server/package.json
+++ b/squad-server/package.json
@@ -15,9 +15,9 @@
"pg": "^8.5.1",
"pg-hstore": "^2.3.3",
"sequelize": "^6.3.5",
- "socket.io": "^3.1.2",
+ "socket.io": "^4.5.4",
"sqlite3": "^5.0.0",
- "tedious": "^9.2.1",
+ "tedious": "^15.1.2",
"tinygradient": "^1.1.2"
},
"exports": {
diff --git a/squad-server/plugins/auto-kick-unassigned.js b/squad-server/plugins/auto-kick-unassigned.js
index 8a8d784e1..1a4c81bb0 100644
--- a/squad-server/plugins/auto-kick-unassigned.js
+++ b/squad-server/plugins/auto-kick-unassigned.js
@@ -17,7 +17,7 @@ export default class AutoKickUnassigned extends BasePlugin {
warningMessage: {
required: false,
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: {
required: false,
diff --git a/squad-server/plugins/discord-base-plugin.js b/squad-server/plugins/discord-base-plugin.js
index 46e5ad13a..26557ed9e 100644
--- a/squad-server/plugins/discord-base-plugin.js
+++ b/squad-server/plugins/discord-base-plugin.js
@@ -15,10 +15,24 @@ export default class DiscordBasePlugin extends BasePlugin {
}
async prepareToMount() {
- this.channel = await this.options.discordClient.channels.fetch(this.options.channelID);
+ try {
+ 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) {
+ if (!this.channel) {
+ this.verbose(1, `Could not send Discord Message. Channel not initialized.`);
+ return;
+ }
+
if (typeof message === 'object' && 'embed' in message)
message.embed.footer = message.embed.footer || { text: COPYRIGHT_MESSAGE };
diff --git a/squad-server/rcon.js b/squad-server/rcon.js
index 8c605b847..7209d7a04 100644
--- a/squad-server/rcon.js
+++ b/squad-server/rcon.js
@@ -139,9 +139,11 @@ export default class SquadRcon extends Rcon {
const players = [];
+ if (!response || response.length < 1) return players;
+
for (const line of response.split('\n')) {
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;
@@ -150,7 +152,9 @@ export default class SquadRcon extends Rcon {
steamID: match[2],
name: match[3],
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 teamID;
+ if (!responseSquad || responseSquad.length < 1) return squads;
+
for (const line of responseSquad.split('\n')) {
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) \((.+)\)/);
if (matchSide) {
@@ -174,11 +180,13 @@ export default class SquadRcon extends Rcon {
teamName = matchSide[2];
}
if (!match) continue;
- await squads.push({
+ squads.push({
squadID: match[1],
squadName: match[2],
size: match[3],
locked: match[4],
+ creatorName: match[5],
+ creatorSteamID: match[6],
teamID: teamID,
teamName: teamName
});