mirror of
https://github.com/AsgardEternal/squad-js-map-vote.git
synced 2025-01-24 01:23:52 -06:00
feat: data persistency
This commit is contained in:
parent
e339b07647
commit
b19310aa20
10
README.MD
10
README.MD
@ -183,6 +183,15 @@ The ID of the channel to log votes to.
|
|||||||
```json
|
```json
|
||||||
"112233445566778899"
|
"112233445566778899"
|
||||||
```
|
```
|
||||||
|
#### persistentDataFile
|
||||||
|
###### Description
|
||||||
|
Path to file in which to store important data that should be restored after a restart.
|
||||||
|
###### Important
|
||||||
|
Make sure the persistent data file is not inside the plugin folder.
|
||||||
|
###### Default
|
||||||
|
```json
|
||||||
|
""
|
||||||
|
```
|
||||||
#### timezone
|
#### timezone
|
||||||
###### Description
|
###### Description
|
||||||
Timezone relative to UTC time. 0 for UTC, 2 for CEST (UTC+2), -1 (UTC-1)
|
Timezone relative to UTC time. 0 for UTC, 2 for CEST (UTC+2), -1 (UTC-1)
|
||||||
@ -235,6 +244,7 @@ Array of timeframes that allows to override options based on local time. See exa
|
|||||||
"allowedSameMapEntries": 1,
|
"allowedSameMapEntries": 1,
|
||||||
"logToDiscord": true,
|
"logToDiscord": true,
|
||||||
"channelID": "112233445566778899",
|
"channelID": "112233445566778899",
|
||||||
|
"persistentDataFile": "",
|
||||||
"timezone": 2,
|
"timezone": 2,
|
||||||
"timeFrames": [
|
"timeFrames": [
|
||||||
{
|
{
|
||||||
|
95
mapvote.js
95
mapvote.js
@ -5,6 +5,8 @@ import DiscordBasePlugin from './discord-base-plugin.js';
|
|||||||
import { Layers } from "../layers/index.js"
|
import { Layers } from "../layers/index.js"
|
||||||
import axios from "axios"
|
import axios from "axios"
|
||||||
import Layer from '../layers/layer.js';
|
import Layer from '../layers/layer.js';
|
||||||
|
import fs from 'fs'
|
||||||
|
import process from 'process'
|
||||||
|
|
||||||
export default class MapVote extends DiscordBasePlugin {
|
export default class MapVote extends DiscordBasePlugin {
|
||||||
static get description() {
|
static get description() {
|
||||||
@ -134,6 +136,11 @@ export default class MapVote extends DiscordBasePlugin {
|
|||||||
default: '',
|
default: '',
|
||||||
example: '112233445566778899'
|
example: '112233445566778899'
|
||||||
},
|
},
|
||||||
|
persistentDataFile: {
|
||||||
|
required: false,
|
||||||
|
description: 'Path to file in which to store important data that should be restored after a restart',
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
timezone: {
|
timezone: {
|
||||||
required: false,
|
required: false,
|
||||||
description: "Timezone relative to UTC time. 0 for UTC, 2 for CEST (UTC+2), -1 (UTC-1) ",
|
description: "Timezone relative to UTC time. 0 for UTC, 2 for CEST (UTC+2), -1 (UTC-1) ",
|
||||||
@ -159,7 +166,6 @@ export default class MapVote extends DiscordBasePlugin {
|
|||||||
this.trackedVotes = {}; //player votes, keyed by steam id
|
this.trackedVotes = {}; //player votes, keyed by steam id
|
||||||
this.tallies = []; //votes per layer, parellel with nominations
|
this.tallies = []; //votes per layer, parellel with nominations
|
||||||
this.votingEnabled = false;
|
this.votingEnabled = false;
|
||||||
this.onConnectBound = false;
|
|
||||||
this.broadcastIntervalTask = null;
|
this.broadcastIntervalTask = null;
|
||||||
this.firstBroadcast = true;
|
this.firstBroadcast = true;
|
||||||
this.newVoteTimeout = null;
|
this.newVoteTimeout = null;
|
||||||
@ -181,13 +187,21 @@ export default class MapVote extends DiscordBasePlugin {
|
|||||||
this.setSeedingMode = this.setSeedingMode.bind(this);
|
this.setSeedingMode = this.setSeedingMode.bind(this);
|
||||||
this.logVoteToDiscord = this.logVoteToDiscord.bind(this);
|
this.logVoteToDiscord = this.logVoteToDiscord.bind(this);
|
||||||
this.timeframeOptionOverrider = this.timeframeOptionOverrider.bind(this);
|
this.timeframeOptionOverrider = this.timeframeOptionOverrider.bind(this);
|
||||||
|
this.savePersistentData = this.savePersistentData.bind(this)
|
||||||
|
this.restorePersistentData = this.restorePersistentData.bind(this)
|
||||||
|
|
||||||
this.broadcast = (msg) => { this.server.rcon.broadcast(msg); };
|
this.broadcast = (msg) => { this.server.rcon.broadcast(msg); };
|
||||||
this.warn = (steamid, msg) => { this.server.rcon.warn(steamid, msg); };
|
this.warn = (steamid, msg) => { this.server.rcon.warn(steamid, msg); };
|
||||||
|
|
||||||
|
process.on('uncaughtException', function (err) {
|
||||||
|
this.savePersistentData();
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async mount() {
|
async mount() {
|
||||||
await this.updateLayerList();
|
await this.updateLayerList();
|
||||||
|
this.restorePersistentData();
|
||||||
this.server.on('NEW_GAME', this.onNewGame);
|
this.server.on('NEW_GAME', this.onNewGame);
|
||||||
this.server.on('CHAT_MESSAGE', this.onChatMessage);
|
this.server.on('CHAT_MESSAGE', this.onChatMessage);
|
||||||
this.server.on('PLAYER_DISCONNECTED', this.onPlayerDisconnected);
|
this.server.on('PLAYER_DISCONNECTED', this.onPlayerDisconnected);
|
||||||
@ -200,6 +214,7 @@ export default class MapVote extends DiscordBasePlugin {
|
|||||||
// await this.checkUpdates();
|
// await this.checkUpdates();
|
||||||
this.timeframeOptionOverrider();
|
this.timeframeOptionOverrider();
|
||||||
setInterval(this.timeframeOptionOverrider, 1 * 60 * 1000)
|
setInterval(this.timeframeOptionOverrider, 1 * 60 * 1000)
|
||||||
|
setInterval(this.savePersistentData, 20 * 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
async unmount() {
|
async unmount() {
|
||||||
@ -399,6 +414,15 @@ export default class MapVote extends DiscordBasePlugin {
|
|||||||
|
|
||||||
await this.warn(steamID, msg + `\nMapVote SquadJS plugin built by JetDave`);
|
await this.warn(steamID, msg + `\nMapVote SquadJS plugin built by JetDave`);
|
||||||
return;
|
return;
|
||||||
|
case "endsqjs":
|
||||||
|
case "closesqjs":
|
||||||
|
case "stopesqjs":
|
||||||
|
case "restartsqjs":
|
||||||
|
if (!isAdmin) return;
|
||||||
|
this.warn(steamID, "Saving persistent data.\nTerminating SquadJS process.\nIf managed by a process manager it will automatically restart.")
|
||||||
|
this.savePersistentData();
|
||||||
|
process.exit(0);
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
//give them an error
|
//give them an error
|
||||||
await this.warn(steamID, `Unknown vote subcommand: ${subCommand}`);
|
await this.warn(steamID, `Unknown vote subcommand: ${subCommand}`);
|
||||||
@ -495,10 +519,11 @@ export default class MapVote extends DiscordBasePlugin {
|
|||||||
|
|
||||||
const sanitizedLayers = Layers.layers.filter((l) => l.layerid && l.map);
|
const sanitizedLayers = Layers.layers.filter((l) => l.layerid && l.map);
|
||||||
const maxOptions = this.options.showRerollOption ? 5 : 6;
|
const maxOptions = this.options.showRerollOption ? 5 : 6;
|
||||||
if (!cmdLayers || cmdLayers.length == 0) {
|
|
||||||
const recentlyPlayedMaps = this.objArrToValArr(this.server.layerHistory.slice(0, this.options.numberRecentMapsToExlude), "layer", "map", "name");
|
|
||||||
this.verbose(1, "Recently played maps: " + recentlyPlayedMaps.filter((l) => l && l.map && l.map.name).map((l) => l.map.name).join(', '))
|
|
||||||
|
|
||||||
|
const recentlyPlayedMaps = this.objArrToValArr(this.server.layerHistory.slice(0, this.options.numberRecentMapsToExlude), "layer", "map", "name");
|
||||||
|
this.verbose(1, "Recently played maps: " + recentlyPlayedMaps.join(', '));//recentlyPlayedMaps.filter((l) => l && l.map && l.map.name).map((l) => l.map.name).join(', '))
|
||||||
|
|
||||||
|
if (!cmdLayers || cmdLayers.length == 0) {
|
||||||
const all_layers = sanitizedLayers.filter((l) =>
|
const all_layers = sanitizedLayers.filter((l) =>
|
||||||
this.options.gamemodeWhitelist.includes(l.gamemode.toUpperCase()) &&
|
this.options.gamemodeWhitelist.includes(l.gamemode.toUpperCase()) &&
|
||||||
![ this.server.currentLayer ? this.server.currentLayer.map.name : null, ...recentlyPlayedMaps ].includes(l.map.name) &&
|
![ this.server.currentLayer ? this.server.currentLayer.map.name : null, ...recentlyPlayedMaps ].includes(l.map.name) &&
|
||||||
@ -531,7 +556,7 @@ export default class MapVote extends DiscordBasePlugin {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (cmdLayers.length == 1) for (let i = 0; i < maxOptions; i++) cmdLayers.push(cmdLayers[ 0 ])
|
if (cmdLayers.length == 1) while (cmdLayers.length < maxOptions) cmdLayers.push(cmdLayers[ 0 ])
|
||||||
|
|
||||||
if (cmdLayers.length <= maxOptions) {
|
if (cmdLayers.length <= maxOptions) {
|
||||||
let i = 1;
|
let i = 1;
|
||||||
@ -764,6 +789,66 @@ export default class MapVote extends DiscordBasePlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
restorePersistentData() {
|
||||||
|
this.verbose(1, `Restoring persistent data from: ${this.options.persistentDataFile}`)
|
||||||
|
|
||||||
|
if (this.options.persistentDataFile == "") return;
|
||||||
|
|
||||||
|
if (!fs.existsSync(this.options.persistentDataFile)) return;
|
||||||
|
|
||||||
|
let bkData = fs.readFileSync(this.options.persistentDataFile);
|
||||||
|
if (bkData == "") return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
bkData = JSON.parse(bkData)
|
||||||
|
} catch (e) {
|
||||||
|
this.verbose(1, "Error restoring persistent data", e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let k in bkData.server) this.server[ k ] = bkData.server[ k ];
|
||||||
|
|
||||||
|
const maxSecondsDiffierence = 60
|
||||||
|
if ((new Date() - new Date(bkData.saveDateTime)) / 1000 > maxSecondsDiffierence) return
|
||||||
|
|
||||||
|
this.verbose(1, "Restoring data:", bkData)
|
||||||
|
|
||||||
|
// if (bkData.custom.layerHistory) this.server.layerHistory = Layers.layers.filter(l => bkData.custom.layerHistory.includes(l.layerid));
|
||||||
|
this.verbose(1, "Recently played maps: " + this.server.layerHistory.filter((l) => l && l.map && l.map.name).map((l) => l.layer.map.name).join(', '))
|
||||||
|
|
||||||
|
for (let k in bkData.plugin) this[ k ] = bkData.plugin[ k ];
|
||||||
|
if (this.votingEnabled) {
|
||||||
|
this.broadcastIntervalTask = setInterval(this.broadcastNominations, toMils(this.options.voteBroadcastInterval));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
savePersistentData() {
|
||||||
|
if (this.options.persistentDataFile == "") return;
|
||||||
|
|
||||||
|
|
||||||
|
const saveDt = {
|
||||||
|
custom: {
|
||||||
|
// layerHistory: this.server.layerHistory.slice(0, this.options.numberRecentMapsToExlude * 2).filter(l => l && l.layerid).map(l => l.layerid),
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
layerHistory: this.server.layerHistory
|
||||||
|
},
|
||||||
|
plugin: {
|
||||||
|
nominations: this.nominations,
|
||||||
|
trackedVotes: this.trackedVotes,
|
||||||
|
tallies: this.tallies,
|
||||||
|
votingEnabled: this.votingEnabled,
|
||||||
|
factionStrings: this.factionStrings,
|
||||||
|
firstBroadcast: this.firstBroadcast
|
||||||
|
},
|
||||||
|
saveDateTime: new Date()
|
||||||
|
}
|
||||||
|
// this.verbose(1, `Saving persistent data to: ${this.options.persistentDataFile}\n`, saveDt.server.layerHistory)
|
||||||
|
|
||||||
|
fs.writeFileSync(this.options.persistentDataFile, JSON.stringify(saveDt, null, 2))
|
||||||
|
}
|
||||||
|
|
||||||
//calculates the current winner(s) of the vote and returns thier strings in an array
|
//calculates the current winner(s) of the vote and returns thier strings in an array
|
||||||
get currentWinners() {
|
get currentWinners() {
|
||||||
const ties = [];
|
const ties = [];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user