diff --git a/README.md b/README.md
index a21144e9..e1b720e3 100644
--- a/README.md
+++ b/README.md
@@ -639,6 +639,29 @@ Grafana:
16761867
+
+ DiscordRoundEnded
+ DiscordRoundEnded
+ The DiscordRoundEnded
plugin will send the round winner to a Discord channel.
+ Options
+ 667741905228136459
+color
+ Description
+ The color of the embed.
+ Default
+ 16761867
+
+
DiscordServerStatus
DiscordServerStatus
diff --git a/config.json b/config.json
index 37470001..e68f5e58 100644
--- a/config.json
+++ b/config.json
@@ -166,6 +166,13 @@
"channelID": "",
"color": 16761867
},
+ {
+ "plugin": "DiscordRoundEnded",
+ "enabled": true,
+ "discordClient": "discord",
+ "channelID": "",
+ "color": 16761867
+ },
{
"plugin": "DiscordServerStatus",
"enabled": true,
diff --git a/squad-server/index.js b/squad-server/index.js
index 60233379..c366be2f 100644
--- a/squad-server/index.js
+++ b/squad-server/index.js
@@ -290,6 +290,10 @@ export default class SquadServer extends EventEmitter {
this.emit('PLAYER_UNPOSSESS', data);
});
+ this.logParser.on('ROUND_ENDED', async (data) => {
+ this.emit('ROUND_ENDED', data);
+ });
+
this.logParser.on('TICK_RATE', (data) => {
this.emit('TICK_RATE', data);
});
diff --git a/squad-server/log-parser/index.js b/squad-server/log-parser/index.js
index 990f41fd..43588684 100644
--- a/squad-server/log-parser/index.js
+++ b/squad-server/log-parser/index.js
@@ -11,6 +11,8 @@ import PlayerPossess from './player-possess.js';
import PlayerRevived from './player-revived.js';
import PlayerUnPossess from './player-un-possess.js';
import PlayerWounded from './player-wounded.js';
+import RoundEnded from './round-ended.js';
+import RoundTickets from './round-tickets.js';
import RoundWinner from './round-winner.js';
import ServerTickRate from './server-tick-rate.js';
import SteamIDConnected from './steamid-connected.js';
@@ -34,6 +36,8 @@ export default class SquadLogParser extends LogParser {
PlayerRevived,
PlayerUnPossess,
PlayerWounded,
+ RoundEnded,
+ RoundTickets,
RoundWinner,
ServerTickRate,
SteamIDConnected,
diff --git a/squad-server/log-parser/round-ended.js b/squad-server/log-parser/round-ended.js
new file mode 100644
index 00000000..4b441992
--- /dev/null
+++ b/squad-server/log-parser/round-ended.js
@@ -0,0 +1,21 @@
+/**
+ * Matches when Map state Changes to PostMatch (ScoreBoard)
+ *
+ * Emits winner and loser from eventstore
+ *
+ * winner and loser may be null if the match ends with a draw
+ */
+export default {
+ regex:
+ /^\[([0-9.:-]+)]\[([ 0-9]*)]LogGameState: Match State Changed from InProgress to WaitingPostMatch/,
+ onMatch: (args, logParser) => {
+ const data = {
+ winner: logParser.eventStore.ROUND_WINNER ? logParser.eventStore.ROUND_WINNER : null,
+ loser: logParser.eventStore.ROUND_LOSER ? logParser.eventStore.ROUND_LOSER : null,
+ time: args[1]
+ };
+ logParser.emit('ROUND_ENDED', data);
+ delete logParser.eventStore.ROUND_WINNER;
+ delete logParser.eventStore.ROUND_LOSER;
+ }
+};
diff --git a/squad-server/log-parser/round-tickets.js b/squad-server/log-parser/round-tickets.js
new file mode 100644
index 00000000..646241bd
--- /dev/null
+++ b/squad-server/log-parser/round-tickets.js
@@ -0,0 +1,28 @@
+/**
+ * Matches when tickets appear in the log
+ *
+ * Will not match on Draw or Map Changes before the game has started
+ */
+export default {
+ regex:
+ /^\[([0-9.:-]+)]\[([ 0-9]*)]LogSquadGameEvents: Display: Team ([0-9]), (.*) \( ?(.*?) ?\) has (won|lost) the match with ([0-9]+) Tickets on layer (.*) \(level (.*)\)!/,
+ onMatch: (args, logParser) => {
+ const data = {
+ raw: args[0],
+ time: args[1],
+ chainID: args[2],
+ team: args[3],
+ subfaction: args[4],
+ faction: args[5],
+ action: args[6],
+ tickets: args[7],
+ layer: args[8],
+ level: args[9]
+ };
+ if (data.action === 'won') {
+ logParser.eventStore.ROUND_WINNER = data;
+ } else {
+ logParser.eventStore.ROUND_LOSER = data;
+ }
+ }
+};
diff --git a/squad-server/plugins/discord-roundended.js b/squad-server/plugins/discord-roundended.js
new file mode 100644
index 00000000..f9757b16
--- /dev/null
+++ b/squad-server/plugins/discord-roundended.js
@@ -0,0 +1,79 @@
+import DiscordBasePlugin from './discord-base-plugin.js';
+
+export default class DiscordRoundEnded extends DiscordBasePlugin {
+ static get description() {
+ return 'The DiscordRoundEnded
plugin will send the round winner to a Discord channel.';
+ }
+
+ static get defaultEnabled() {
+ return true;
+ }
+
+ static get optionsSpecification() {
+ return {
+ ...DiscordBasePlugin.optionsSpecification,
+ channelID: {
+ required: true,
+ description: 'The ID of the channel to log round end events to.',
+ default: '',
+ example: '667741905228136459'
+ },
+ color: {
+ required: false,
+ description: 'The color of the embed.',
+ default: 16761867
+ }
+ };
+ }
+
+ constructor(server, options, connectors) {
+ super(server, options, connectors);
+
+ this.onRoundEnd = this.onRoundEnd.bind(this);
+ }
+
+ async mount() {
+ this.server.on('ROUND_ENDED', this.onRoundEnd);
+ }
+
+ async unmount() {
+ this.server.removeEventListener('ROUND_ENDED', this.onRoundEnd);
+ }
+
+ async onRoundEnd(info) {
+ if (!info.winner || !info.loser) {
+ await this.sendDiscordMessage({
+ embed: {
+ title: 'Round Ended',
+ description: 'This match Ended in a Draw',
+ color: this.options.color,
+ timestamp: info.time.toISOString()
+ }
+ });
+ return;
+ }
+
+ await this.sendDiscordMessage({
+ embed: {
+ title: 'Round Ended',
+ description: `${info.winner.layer} - ${info.winner.level}`,
+ color: this.options.color,
+ fields: [
+ {
+ name: `Team ${info.winner.team} Won`,
+ value: `${info.winner.subfaction}\n ${info.winner.faction}\n won with ${info.winner.tickets} tickets.`
+ },
+ {
+ name: `Team ${info.loser.team} Lost`,
+ value: `${info.loser.subfaction}\n ${info.loser.faction}\n lost with ${info.loser.tickets} tickets.`
+ },
+ {
+ name: 'Ticket Difference',
+ value: `${info.winner.tickets - info.loser.tickets}.`
+ }
+ ],
+ timestamp: info.time.toISOString()
+ }
+ });
+ }
+}