mirror of
https://github.com/AsgardEternal/SquadJS.git
synced 2024-09-28 16:24:25 -05:00
commit
d401ee3561
@ -1,4 +1,4 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"printWidth": 80
|
||||
"printWidth": 100
|
||||
}
|
@ -209,7 +209,11 @@
|
||||
},
|
||||
"tanks": "x1 for INS, 30 min delay",
|
||||
"helicopters": "N/A",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 45,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Al Basrah TC v2",
|
||||
@ -232,7 +236,11 @@
|
||||
},
|
||||
"tanks": "x1 for INS, 20 min delay",
|
||||
"helicopters": "N/A",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 45,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Belaya AAS v1",
|
||||
@ -471,7 +479,11 @@
|
||||
},
|
||||
"tanks": "x1 per team, 20min delay",
|
||||
"helicopters": "N/A",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 45,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Chora AAS v1",
|
||||
@ -710,12 +722,16 @@
|
||||
},
|
||||
"tanks": "N/A",
|
||||
"helicopters": "N/A",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 36,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Fool's Road AAS v1",
|
||||
"map": "Fool's Road",
|
||||
"layerClassname": "FoolsRoad_AAS_v1",
|
||||
"layerClassname": "Fools_Road_AAS_v1",
|
||||
"mapSize": "2x2 km",
|
||||
"gamemode": "AAS",
|
||||
"version": "v1",
|
||||
@ -742,7 +758,7 @@
|
||||
{
|
||||
"layer": "Fool's Road AAS v2",
|
||||
"map": "Fool's Road",
|
||||
"layerClassname": "FoolsRoad_AAS_v2",
|
||||
"layerClassname": "Fools_Road_AAS_v2",
|
||||
"mapSize": "2x2 km",
|
||||
"gamemode": "AAS",
|
||||
"version": "v2",
|
||||
@ -769,7 +785,7 @@
|
||||
{
|
||||
"layer": "Fool's Road Destruction v1",
|
||||
"map": "Fool's Road",
|
||||
"layerClassname": "FoolsRoad_Destruction_v1",
|
||||
"layerClassname": "Fools_Road_Destruction_v1",
|
||||
"mapSize": "2x2 km",
|
||||
"gamemode": "Destruction",
|
||||
"version": "v1",
|
||||
@ -796,7 +812,7 @@
|
||||
{
|
||||
"layer": "Fool's Road Invasion v1",
|
||||
"map": "Fool's Road",
|
||||
"layerClassname": "FoolsRoad_Invasion_v1",
|
||||
"layerClassname": "Fools_Road_Invasion_v1",
|
||||
"mapSize": "2x2 km",
|
||||
"gamemode": "Invasion",
|
||||
"version": "v1",
|
||||
@ -823,7 +839,7 @@
|
||||
{
|
||||
"layer": "Fool's Road RAAS v1",
|
||||
"map": "Fool's Road",
|
||||
"layerClassname": "FoolsRoad_RAAS_v1",
|
||||
"layerClassname": "Fools_Road_RAAS_v1",
|
||||
"mapSize": "2x2 km",
|
||||
"gamemode": "RAAS",
|
||||
"version": "v1",
|
||||
@ -850,7 +866,7 @@
|
||||
{
|
||||
"layer": "Fool's Road RAAS v2",
|
||||
"map": "Fool's Road",
|
||||
"layerClassname": "FoolsRoad_RAAS_v2",
|
||||
"layerClassname": "Fools_Road_RAAS_v2",
|
||||
"mapSize": "2x2 km",
|
||||
"gamemode": "RAAS",
|
||||
"version": "v2",
|
||||
@ -877,7 +893,7 @@
|
||||
{
|
||||
"layer": "Fool's Road RAAS v3",
|
||||
"map": "Fool's Road",
|
||||
"layerClassname": "FoolsRoad_RAAS_v3",
|
||||
"layerClassname": "Fools_Road_RAAS_v3",
|
||||
"mapSize": "2x2 km",
|
||||
"gamemode": "RAAS",
|
||||
"version": "v3",
|
||||
@ -904,7 +920,7 @@
|
||||
{
|
||||
"layer": "Fool's Road Skirmish v1",
|
||||
"map": "Fool's Road",
|
||||
"layerClassname": "FoolsRoad_Skirmish_v1",
|
||||
"layerClassname": "Fools_Road_Skirmish_v1",
|
||||
"mapSize": "2x2 km",
|
||||
"gamemode": "Skirmish",
|
||||
"version": "v1",
|
||||
@ -931,7 +947,7 @@
|
||||
{
|
||||
"layer": "Fool's Road Skirmish v2",
|
||||
"map": "Fool's Road",
|
||||
"layerClassname": "FoolsRoad_Skirmish_v2",
|
||||
"layerClassname": "Fools_Road_Skirmish_v2",
|
||||
"mapSize": "2x2 km",
|
||||
"gamemode": "Skirmish",
|
||||
"version": "v2",
|
||||
@ -958,7 +974,7 @@
|
||||
{
|
||||
"layer": "Fool's Road TC v1",
|
||||
"map": "Fool's Road",
|
||||
"layerClassname": "FoolsRoad_TC_v1",
|
||||
"layerClassname": "Fools_Road_TC_v1",
|
||||
"mapSize": "2x2 km",
|
||||
"gamemode": "TC",
|
||||
"version": "v1",
|
||||
@ -976,7 +992,11 @@
|
||||
},
|
||||
"tanks": "N/A",
|
||||
"helicopters": "N/A",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 36,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Gorodok AAS v1",
|
||||
@ -1296,7 +1316,11 @@
|
||||
},
|
||||
"tanks": "N/A",
|
||||
"helicopters": "x1 per team",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 45,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Jensen's Range Training v1",
|
||||
@ -1697,7 +1721,11 @@
|
||||
},
|
||||
"tanks": "N/A",
|
||||
"helicopters": "x1 per team",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 45,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Kamdesh TC v2",
|
||||
@ -1720,7 +1748,11 @@
|
||||
},
|
||||
"tanks": "N/A",
|
||||
"helicopters": "N/A",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 54,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Kohat AAS v1",
|
||||
@ -1986,7 +2018,11 @@
|
||||
},
|
||||
"tanks": "N/A",
|
||||
"helicopters": "x2 per team",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 45,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Kokan AAS v1",
|
||||
@ -2171,7 +2207,11 @@
|
||||
},
|
||||
"tanks": "N/A",
|
||||
"helicopters": "N/A",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 36,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Logar Valley AAS v1",
|
||||
@ -2329,7 +2369,11 @@
|
||||
},
|
||||
"tanks": "N/A",
|
||||
"helicopters": "N/A",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 36,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Mestia AAS v1",
|
||||
@ -2487,7 +2531,11 @@
|
||||
},
|
||||
"tanks": "N/A",
|
||||
"helicopters": "N/A",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 36,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Mutaha AAS v1",
|
||||
@ -2618,7 +2666,11 @@
|
||||
},
|
||||
"tanks": "N/A",
|
||||
"helicopters": "N/A",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 36,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Mutaha TC v2",
|
||||
@ -2641,7 +2693,11 @@
|
||||
},
|
||||
"tanks": "x1 per team, 20min delay",
|
||||
"helicopters": "x1 per team",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 54,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Narva AAS v1",
|
||||
@ -2880,7 +2936,11 @@
|
||||
},
|
||||
"tanks": "N/A",
|
||||
"helicopters": "N/A",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 36,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Narva TC v2",
|
||||
@ -2903,7 +2963,11 @@
|
||||
},
|
||||
"tanks": "x1 per team, 30min delay",
|
||||
"helicopters": "N/A",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 45,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Skorpo AAS v1",
|
||||
@ -3142,7 +3206,11 @@
|
||||
},
|
||||
"tanks": "N/A",
|
||||
"helicopters": "N/A",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 54,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Skorpo TC v2",
|
||||
@ -3165,7 +3233,11 @@
|
||||
},
|
||||
"tanks": "N/A",
|
||||
"helicopters": "N/A",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 54,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Skorpo TC v3",
|
||||
@ -3188,7 +3260,11 @@
|
||||
},
|
||||
"tanks": "x1 per team, 20min delay",
|
||||
"helicopters": "N/A",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 45,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Sumari AAS v1",
|
||||
@ -3373,7 +3449,11 @@
|
||||
},
|
||||
"tanks": "N/A",
|
||||
"helicopters": "N/A",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 36,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Tallil Outskirts AAS v1",
|
||||
@ -3739,7 +3819,11 @@
|
||||
},
|
||||
"tanks": "x2 per team, 20min delay",
|
||||
"helicopters": "x2 per team",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 54,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Tutorials Infantry Training Tutorial",
|
||||
@ -4159,7 +4243,11 @@
|
||||
},
|
||||
"tanks": "x2 per team, 20min delay",
|
||||
"helicopters": "x1 per team",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 54,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "Yehorivka TC v2",
|
||||
@ -4182,7 +4270,11 @@
|
||||
},
|
||||
"tanks": "x1 per team",
|
||||
"helicopters": "x1 per team",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 54,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "CAF_Albasrah_Invasion_v1",
|
||||
@ -4313,7 +4405,11 @@
|
||||
},
|
||||
"tanks": "N/A",
|
||||
"helicopters": "x1 per team",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 45,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "CAF_Jensens_Range_v4",
|
||||
@ -4417,7 +4513,11 @@
|
||||
},
|
||||
"tanks": "N/A",
|
||||
"helicopters": "N/A",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 40,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "CAF_Kohat_Invasion_v1",
|
||||
@ -4447,7 +4547,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "CAF_Manic_AAS_v1",
|
||||
"layer": "CAF_Manic-5_AAS_v1",
|
||||
"map": "CAF Manic-5",
|
||||
"layerClassname": "CAF_Manic_AAS_v1",
|
||||
"gamemode": "AAS",
|
||||
@ -4474,7 +4574,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "CAF_Manic_Invasion_v1",
|
||||
"layer": "CAF_Manic-5_Invasion_v1",
|
||||
"map": "CAF Manic-5",
|
||||
"layerClassname": "CAF_Manic_Invasion_v1",
|
||||
"gamemode": "Invasion",
|
||||
@ -4501,7 +4601,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "CAF_Manic_Invasion_v2",
|
||||
"layer": "CAF_Manic-5_Invasion_v2",
|
||||
"map": "CAF Manic-5",
|
||||
"layerClassname": "CAF_Manic_Invasion_v2",
|
||||
"gamemode": "Invasion",
|
||||
@ -4528,7 +4628,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "CAF_Manic_RAAS_v1",
|
||||
"layer": "CAF_Manic-5_RAAS_v1",
|
||||
"map": "CAF Manic-5",
|
||||
"layerClassname": "CAF_Manic_RAAS_v1",
|
||||
"gamemode": "RAAS",
|
||||
@ -4555,7 +4655,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "CAF_Manic_RAAS_v2",
|
||||
"layer": "CAF_Manic-5_RAAS_v2",
|
||||
"map": "CAF Manic-5",
|
||||
"layerClassname": "CAF_Manic_RAAS_v2",
|
||||
"gamemode": "RAAS",
|
||||
@ -4582,7 +4682,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "CAF_Manic_RAAS_v3",
|
||||
"layer": "CAF_Manic-5_RAAS_v3",
|
||||
"map": "CAF Manic-5",
|
||||
"layerClassname": "CAF_Manic_RAAS_v3",
|
||||
"gamemode": "RAAS",
|
||||
@ -4609,7 +4709,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "CAF_Manic_RAAS_v4",
|
||||
"layer": "CAF_Manic-5_RAAS_v4",
|
||||
"map": "CAF Manic-5",
|
||||
"layerClassname": "CAF_Manic_RAAS_v4",
|
||||
"gamemode": "RAAS",
|
||||
@ -4636,7 +4736,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "CAF_Manic_Skirmish_v1",
|
||||
"layer": "CAF_Manic-5_Skirmish_v1",
|
||||
"map": "CAF Manic-5",
|
||||
"layerClassname": "CAF_Manic_Skirmish_v1",
|
||||
"gamemode": "Skirmish",
|
||||
@ -4663,7 +4763,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "CAF_Manic_Skirmish_v2",
|
||||
"layer": "CAF_Manic-5_Skirmish_v2",
|
||||
"map": "CAF Manic-5",
|
||||
"layerClassname": "CAF_Manic_Skirmish_v2",
|
||||
"gamemode": "Skirmish",
|
||||
@ -4690,7 +4790,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "CAF_Manic_TC_v1",
|
||||
"layer": "CAF_Manic-5_TC_v1",
|
||||
"map": "CAF Manic-5",
|
||||
"layerClassname": "CAF_Manic_TC_v1",
|
||||
"gamemode": "TC",
|
||||
@ -4710,7 +4810,11 @@
|
||||
},
|
||||
"tanks": "N/A",
|
||||
"helicopters": "x1 per team",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 45,
|
||||
"max": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"layer": "CAF_Mestia_RAAS_v1",
|
||||
@ -4949,6 +5053,10 @@
|
||||
},
|
||||
"tanks": "N/A",
|
||||
"helicopters": "x1 per team",
|
||||
"newForVersion": false
|
||||
"newForVersion": false,
|
||||
"estimatedSuitablePlayerCount": {
|
||||
"min": 45,
|
||||
"max": 80
|
||||
}
|
||||
}
|
||||
]
|
@ -1,7 +1,5 @@
|
||||
import fs from 'fs';
|
||||
import SquadLayers, {
|
||||
SquadLayers as SquadLayersClass
|
||||
} from './squad-layers.js';
|
||||
import SquadLayers, { SquadLayers as SquadLayersClass } from './squad-layers.js';
|
||||
|
||||
export default class SquadLayerFilter extends SquadLayersClass {
|
||||
constructor(layers, activeLayerFilter = null) {
|
||||
@ -18,7 +16,20 @@ export default class SquadLayerFilter extends SquadLayersClass {
|
||||
// defaults as off
|
||||
...activeLayerFilter.gamemodeHistoryTolerance
|
||||
},
|
||||
gamemodeRepetitiveTolerance: {
|
||||
// defaults as off
|
||||
...activeLayerFilter.gamemodeRepetitiveTolerance
|
||||
},
|
||||
playerCountComplianceEnabled: true,
|
||||
factionComplianceEnabled: true,
|
||||
factionHistoryTolerance: {
|
||||
// defaults as off
|
||||
...activeLayerFilter.factionHistoryTolerance
|
||||
},
|
||||
factionRepetitiveTolerance: {
|
||||
// defaults as off
|
||||
...activeLayerFilter.factionRepetitiveTolerance
|
||||
},
|
||||
...activeLayerFilter
|
||||
};
|
||||
}
|
||||
@ -31,26 +42,20 @@ export default class SquadLayerFilter extends SquadLayersClass {
|
||||
static buildFromDidYouMeanList(layerNames, activeLayerFilter) {
|
||||
const layers = [];
|
||||
for (const layerName of layerNames) {
|
||||
const layer = SquadLayers.getLayerByDidYouMean(
|
||||
layerName,
|
||||
SquadLayers.getLayerNames()
|
||||
);
|
||||
const layer = SquadLayers.getLayerByDidYouMean(layerName, SquadLayers.getLayerNames());
|
||||
if (layer) layers.push(layer);
|
||||
}
|
||||
return new SquadLayerFilter(layers, activeLayerFilter);
|
||||
}
|
||||
|
||||
static buildFromFile(filename, activeLayerFilter, delimiter = '\n') {
|
||||
const lines = fs
|
||||
.readFileSync('./connectors/data/layers.json', 'utf8')
|
||||
.split(delimiter);
|
||||
const lines = fs.readFileSync('./connectors/data/layers.json', 'utf8').split(delimiter);
|
||||
const layers = [];
|
||||
|
||||
const validLayerNames = SquadLayers.getLayerNames();
|
||||
|
||||
for (const line of lines) {
|
||||
if (validLayerNames.contains(line))
|
||||
layers.push(SquadLayers.getLayerByLayerName(line));
|
||||
if (validLayerNames.contains(line)) layers.push(SquadLayers.getLayerByLayerName(line));
|
||||
}
|
||||
return new SquadLayerFilter(layers, activeLayerFilter);
|
||||
}
|
||||
@ -72,31 +77,16 @@ export default class SquadLayerFilter extends SquadLayersClass {
|
||||
|
||||
for (const layer of SquadLayers.getLayers()) {
|
||||
// Whitelist / Blacklist Layers
|
||||
if (
|
||||
whitelistedLayers !== null &&
|
||||
!whitelistedLayers.includes(layer.layer)
|
||||
)
|
||||
continue;
|
||||
if (blacklistedLayers !== null && blacklistedLayers.includes(layer.layer))
|
||||
continue;
|
||||
if (whitelistedLayers !== null && !whitelistedLayers.includes(layer.layer)) continue;
|
||||
if (blacklistedLayers !== null && blacklistedLayers.includes(layer.layer)) continue;
|
||||
|
||||
// Whitelist / Blacklist Maps
|
||||
if (whitelistedMaps !== null && !whitelistedMaps.includes(layer.map))
|
||||
continue;
|
||||
if (blacklistedMaps !== null && blacklistedMaps.includes(layer.map))
|
||||
continue;
|
||||
if (whitelistedMaps !== null && !whitelistedMaps.includes(layer.map)) continue;
|
||||
if (blacklistedMaps !== null && blacklistedMaps.includes(layer.map)) continue;
|
||||
|
||||
// Whitelist / Blacklist Gamemodes
|
||||
if (
|
||||
whitelistedGamemodes !== null &&
|
||||
!whitelistedGamemodes.includes(layer.gamemode)
|
||||
)
|
||||
continue;
|
||||
if (
|
||||
blacklistedGamemodes !== null &&
|
||||
blacklistedGamemodes.includes(layer.gamemode)
|
||||
)
|
||||
continue;
|
||||
if (whitelistedGamemodes !== null && !whitelistedGamemodes.includes(layer.gamemode)) continue;
|
||||
if (blacklistedGamemodes !== null && blacklistedGamemodes.includes(layer.gamemode)) continue;
|
||||
|
||||
// Flag Count
|
||||
if (flagCountMin !== null && layer.flagCount < flagCountMin) continue;
|
||||
@ -105,11 +95,7 @@ export default class SquadLayerFilter extends SquadLayersClass {
|
||||
// Other Properties
|
||||
if (hasCommander !== null && layer.commander !== hasCommander) continue;
|
||||
if (hasTanks !== null && (layer.tanks !== 'N/A') !== hasTanks) continue;
|
||||
if (
|
||||
hasHelicopters !== null &&
|
||||
(layer.helicopters !== 'N/A') !== hasHelicopters
|
||||
)
|
||||
continue;
|
||||
if (hasHelicopters !== null && (layer.helicopters !== 'N/A') !== hasHelicopters) continue;
|
||||
|
||||
layers.push(layer);
|
||||
}
|
||||
@ -129,17 +115,10 @@ export default class SquadLayerFilter extends SquadLayersClass {
|
||||
|
||||
for (
|
||||
let i = 0;
|
||||
i <
|
||||
Math.min(
|
||||
server.layerHistory.length,
|
||||
this.activeLayerFilter.layerHistoryTolerance
|
||||
);
|
||||
i < Math.min(server.layerHistory.length, this.activeLayerFilter.layerHistoryTolerance);
|
||||
i++
|
||||
) {
|
||||
if (
|
||||
new Date() - server.layerHistory[i].time >
|
||||
this.activeLayerFilter.historyResetTime
|
||||
)
|
||||
if (new Date() - server.layerHistory[i].time > this.activeLayerFilter.historyResetTime)
|
||||
return true;
|
||||
if (server.layerHistory[i].layer === layer) return false;
|
||||
}
|
||||
@ -149,23 +128,16 @@ export default class SquadLayerFilter extends SquadLayersClass {
|
||||
isMapHistoryCompliant(server, layer) {
|
||||
if (this.activeLayerFilter === null) return true;
|
||||
|
||||
if (typeof layer === 'string')
|
||||
layer = SquadLayers.getLayerByLayerName(layer);
|
||||
if (typeof layer === 'string') layer = SquadLayers.getLayerByLayerName(layer);
|
||||
|
||||
for (
|
||||
let i = 0;
|
||||
i <
|
||||
Math.min(
|
||||
server.layerHistory.length,
|
||||
this.activeLayerFilter.mapHistoryTolerance
|
||||
);
|
||||
i < Math.min(server.layerHistory.length, this.activeLayerFilter.mapHistoryTolerance);
|
||||
i++
|
||||
) {
|
||||
if (
|
||||
new Date() - server.layerHistory[i].time >
|
||||
this.activeLayerFilter.historyResetTime
|
||||
)
|
||||
if (new Date() - server.layerHistory[i].time > this.activeLayerFilter.historyResetTime)
|
||||
return true;
|
||||
|
||||
if (server.layerHistory[i].map === layer.map) return false;
|
||||
}
|
||||
return true;
|
||||
@ -174,42 +146,134 @@ export default class SquadLayerFilter extends SquadLayersClass {
|
||||
isGamemodeHistoryCompliant(server, layer) {
|
||||
if (this.activeLayerFilter === null) return true;
|
||||
|
||||
if (typeof layer === 'string')
|
||||
layer = SquadLayers.getLayerByLayerName(layer);
|
||||
if (typeof layer === 'string') layer = SquadLayers.getLayerByLayerName(layer);
|
||||
|
||||
const gamemodeHistoryTolerance = this.activeLayerFilter
|
||||
.gamemodeHistoryTolerance[layer.gamemode];
|
||||
const gamemodeHistoryTolerance = this.activeLayerFilter.gamemodeHistoryTolerance[
|
||||
layer.gamemode
|
||||
];
|
||||
if (!gamemodeHistoryTolerance) return true;
|
||||
|
||||
for (
|
||||
let i = 0;
|
||||
i < Math.min(server.layerHistory.length, gamemodeHistoryTolerance);
|
||||
i++
|
||||
) {
|
||||
if (
|
||||
new Date() - server.layerHistory[i].time >
|
||||
this.activeLayerFilter.historyResetTime
|
||||
)
|
||||
for (let i = 0; i < Math.min(server.layerHistory.length, gamemodeHistoryTolerance); i++) {
|
||||
if (new Date() - server.layerHistory[i].time > this.activeLayerFilter.historyResetTime)
|
||||
return true;
|
||||
|
||||
const historyLayer = SquadLayers.getLayerByLayerName(
|
||||
server.layerHistory[i].layer
|
||||
);
|
||||
if (historyLayer && historyLayer.gamemode === layer.gamemode)
|
||||
return false;
|
||||
const historyLayer = SquadLayers.getLayerByLayerName(server.layerHistory[i].layer);
|
||||
if (!historyLayer) continue;
|
||||
|
||||
if (historyLayer.gamemode === layer.gamemode) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
isGamemodeRepetitiveCompliant(server, layer) {
|
||||
if (this.activeLayerFilter === null) return true;
|
||||
|
||||
if (typeof layer === 'string') layer = SquadLayers.getLayerByLayerName(layer);
|
||||
|
||||
const gamemodeRepetitiveTolerance = this.activeLayerFilter.gamemodeRepetitiveTolerance[
|
||||
layer.gamemode
|
||||
];
|
||||
if (!gamemodeRepetitiveTolerance) return true;
|
||||
|
||||
for (let i = 0; i < Math.min(server.layerHistory.length, gamemodeRepetitiveTolerance); i++) {
|
||||
if (new Date() - server.layerHistory[i].time > this.activeLayerFilter.historyResetTime)
|
||||
return true;
|
||||
|
||||
const historyLayer = SquadLayers.getLayerByLayerName(server.layerHistory[i].layer);
|
||||
if (!historyLayer) return true;
|
||||
|
||||
if (historyLayer.gamemode !== layer.gamemode) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
isFactionCompliant(server, layer) {
|
||||
if (
|
||||
this.activeLayerFilter === null ||
|
||||
this.activeLayerFilter.factionComplianceEnabled === false
|
||||
)
|
||||
return true;
|
||||
if (server.layerHistory.length === 0) return true;
|
||||
|
||||
if (typeof layer === 'string') layer = SquadLayers.getLayerByLayerName(layer);
|
||||
|
||||
const historyLayer = SquadLayers.getLayerByLayerName(server.layerHistory[0].layer);
|
||||
|
||||
return (
|
||||
!historyLayer ||
|
||||
(
|
||||
historyLayer.teamOne.faction !== layer.teamTwo.faction &&
|
||||
historyLayer.teamTwo.faction !== layer.teamOne.faction
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
isFactionHistoryCompliant(server, layer, faction = null) {
|
||||
if (this.activeLayerFilter === null) return true;
|
||||
|
||||
if (typeof layer === 'string') layer = SquadLayers.getLayerByLayerName(layer);
|
||||
|
||||
if (faction === null) {
|
||||
return (
|
||||
this.isFactionHistoryCompliant(server, layer, layer.teamOne.faction) &&
|
||||
this.isFactionHistoryCompliant(server, layer, layer.teamTwo.faction)
|
||||
);
|
||||
} else {
|
||||
const factionThreshold = this.activeLayerFilter.factionHistoryTolerance[faction];
|
||||
if (!factionThreshold) return true;
|
||||
|
||||
for (let i = 0; i < Math.min(server.layerHistory.length, factionThreshold); i++) {
|
||||
if (new Date() - server.layerHistory[i].time > this.activeLayerFilter.historyResetTime)
|
||||
return true;
|
||||
|
||||
const historyLayer = SquadLayers.getLayerByLayerName(server.layerHistory[i].layer);
|
||||
if (!historyLayer) continue;
|
||||
|
||||
if (historyLayer.teamOne.faction === faction || historyLayer.teamTwo.faction === faction)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
isFactionRepetitiveCompliant(server, layer, faction = null) {
|
||||
if (this.activeLayerFilter === null) return true;
|
||||
|
||||
if (typeof layer === 'string') layer = SquadLayers.getLayerByLayerName(layer);
|
||||
|
||||
if (faction === null) {
|
||||
return (
|
||||
this.isFactionRepetitiveCompliant(server, layer, layer.teamOne.faction) &&
|
||||
this.isFactionRepetitiveCompliant(server, layer, layer.teamTwo.faction)
|
||||
);
|
||||
} else {
|
||||
const factionThreshold = this.activeLayerFilter.factionRepetitiveTolerance[faction];
|
||||
if (!factionThreshold) return true;
|
||||
|
||||
for (let i = 0; i < Math.min(server.layerHistory.length, factionThreshold); i++) {
|
||||
if (new Date() - server.layerHistory[i].time > this.activeLayerFilter.historyResetTime)
|
||||
return true;
|
||||
|
||||
const historyLayer = SquadLayers.getLayerByLayerName(server.layerHistory[i].layer);
|
||||
if (!historyLayer) return true;
|
||||
|
||||
if (historyLayer.teamOne.faction !== faction && historyLayer.teamTwo.faction !== faction)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
isPlayerCountCompliant(server, layer) {
|
||||
if (
|
||||
this.activeLayerFilter === null ||
|
||||
this.playerCountComplianceEnabled === false
|
||||
this.activeLayerFilter.playerCountComplianceEnabled === false
|
||||
)
|
||||
return true;
|
||||
|
||||
if (typeof layer === 'string')
|
||||
layer = SquadLayers.getLayerByLayerName(layer);
|
||||
if (typeof layer === 'string') layer = SquadLayers.getLayerByLayerName(layer);
|
||||
|
||||
return !(
|
||||
server.players.length > layer.estimatedSuitablePlayerCount.max ||
|
||||
|
@ -7,9 +7,7 @@ class SquadLayers {
|
||||
if (Array.isArray(layers)) {
|
||||
this.layers = layers;
|
||||
} else {
|
||||
this.layers = JSON.parse(
|
||||
fs.readFileSync('./connectors/data/layers.json', 'utf8')
|
||||
);
|
||||
this.layers = JSON.parse(fs.readFileSync('./connectors/data/layers.json', 'utf8'));
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.layers.length; i++) {
|
||||
@ -34,9 +32,7 @@ class SquadLayers {
|
||||
}
|
||||
|
||||
getLayerByLayerClassname(layerClassname) {
|
||||
const layer = this.layers.filter(
|
||||
layer => layer.layerClassname === layerClassname
|
||||
);
|
||||
const layer = this.layers.filter(layer => layer.layerClassname === layerClassname);
|
||||
return layer.length === 1 ? layer[0] : null;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "SquadJS",
|
||||
"version": "1.0.10",
|
||||
"version": "1.0.11",
|
||||
"repository": "https://github.com/Thomas-Smyth/SquadJS.git",
|
||||
"author": "Thomas Smyth <https://github.com/Thomas-Smyth>",
|
||||
"license": "MIT",
|
||||
|
@ -2,9 +2,7 @@ import { LOG_PARSER_TEAMKILL } from 'squad-server/events/log-parser';
|
||||
|
||||
export default async function(server, options = {}) {
|
||||
if (!server)
|
||||
throw new Error(
|
||||
'DiscordAdminCamLogs must be provided with a reference to the server.'
|
||||
);
|
||||
throw new Error('DiscordAdminCamLogs must be provided with a reference to the server.');
|
||||
|
||||
server.on(LOG_PARSER_TEAMKILL, info => {
|
||||
// ignore suicides
|
||||
|
@ -6,17 +6,12 @@ import {
|
||||
|
||||
export default async function(server, discordClient, channelID, options = {}) {
|
||||
if (!server)
|
||||
throw new Error(
|
||||
'DiscordAdminCamLogs must be provided with a reference to the server.'
|
||||
);
|
||||
throw new Error('DiscordAdminCamLogs must be provided with a reference to the server.');
|
||||
|
||||
if (!discordClient)
|
||||
throw new Error(
|
||||
'DiscordAdminCamLogs must be provided with a Discord.js client.'
|
||||
);
|
||||
throw new Error('DiscordAdminCamLogs must be provided with a Discord.js client.');
|
||||
|
||||
if (!channelID)
|
||||
throw new Error('DiscordAdminCamLogs must be provided with a channel ID.');
|
||||
if (!channelID) throw new Error('DiscordAdminCamLogs must be provided with a channel ID.');
|
||||
|
||||
options = {
|
||||
color: 16761867,
|
||||
@ -57,8 +52,7 @@ export default async function(server, discordClient, channelID, options = {}) {
|
||||
});
|
||||
|
||||
server.on(LOG_PARSER_PLAYER_UNPOSSESS, info => {
|
||||
if (info.switchPossess === true || !(info.player.steamID in adminsInCam))
|
||||
return;
|
||||
if (info.switchPossess === true || !(info.player.steamID in adminsInCam)) return;
|
||||
|
||||
channel.send({
|
||||
embed: {
|
||||
@ -78,9 +72,7 @@ export default async function(server, discordClient, channelID, options = {}) {
|
||||
{
|
||||
name: 'Time in Admin Camera',
|
||||
value: `${Math.round(
|
||||
(info.time.getTime() -
|
||||
adminsInCam[info.player.steamID].getTime()) /
|
||||
60000
|
||||
(info.time.getTime() - adminsInCam[info.player.steamID].getTime()) / 60000
|
||||
)} mins`
|
||||
}
|
||||
],
|
||||
|
@ -2,16 +2,11 @@ import { COPYRIGHT_MESSAGE } from 'core/config';
|
||||
import { RCON_CHAT_MESSAGE } from 'squad-server/events/rcon';
|
||||
|
||||
export default async function(server, discordClient, channelID, options = {}) {
|
||||
if (!server)
|
||||
throw new Error(
|
||||
'DiscordChat must be provided with a reference to the server.'
|
||||
);
|
||||
if (!server) throw new Error('DiscordChat must be provided with a reference to the server.');
|
||||
|
||||
if (!discordClient)
|
||||
throw new Error('DiscordChat must be provided with a Discord.js client.');
|
||||
if (!discordClient) throw new Error('DiscordChat must be provided with a Discord.js client.');
|
||||
|
||||
if (!channelID)
|
||||
throw new Error('DiscordChat must be provided with a channel ID.');
|
||||
if (!channelID) throw new Error('DiscordChat must be provided with a channel ID.');
|
||||
|
||||
const ignoreChats = options.ignoreChats || ['ChatSquad', 'ChatAdmin'];
|
||||
|
||||
@ -44,8 +39,7 @@ export default async function(server, discordClient, channelID, options = {}) {
|
||||
},
|
||||
{
|
||||
name: 'Team & Squad',
|
||||
value: `Team: ${playerInfo.teamID}, Squad: ${playerInfo.squadID ||
|
||||
'Unassigned'}`
|
||||
value: `Team: ${playerInfo.teamID}, Squad: ${playerInfo.squadID || 'Unassigned'}`
|
||||
},
|
||||
{
|
||||
name: 'Message',
|
||||
|
@ -1,14 +1,9 @@
|
||||
export default async function(server, discordClient, channelID, events = []) {
|
||||
if (!server)
|
||||
throw new Error(
|
||||
'DiscordDebug must be provided with a reference to the server.'
|
||||
);
|
||||
if (!server) throw new Error('DiscordDebug must be provided with a reference to the server.');
|
||||
|
||||
if (!discordClient)
|
||||
throw new Error('DiscordDebug must be provided with a Discord.js client.');
|
||||
if (!discordClient) throw new Error('DiscordDebug must be provided with a Discord.js client.');
|
||||
|
||||
if (!channelID)
|
||||
throw new Error('DicordDebug must be provided with a channel ID.');
|
||||
if (!channelID) throw new Error('DicordDebug must be provided with a channel ID.');
|
||||
|
||||
const channel = await discordClient.channels.fetch(channelID);
|
||||
|
||||
|
@ -43,10 +43,7 @@ function makeEmbed(server, options) {
|
||||
embed: {
|
||||
title: server.serverName,
|
||||
color: options.colorGradient
|
||||
? parseInt(
|
||||
gradient.rgbAt(server.playerCount / server.publicSlots).toHex(),
|
||||
16
|
||||
)
|
||||
? parseInt(gradient.rgbAt(server.playerCount / server.publicSlots).toHex(), 16)
|
||||
: options.color,
|
||||
fields: fields,
|
||||
timestamp: new Date().toISOString(),
|
||||
@ -58,13 +55,9 @@ function makeEmbed(server, options) {
|
||||
}
|
||||
|
||||
export default async function(server, discordClient, options = {}) {
|
||||
if (!server)
|
||||
throw new Error(
|
||||
'DiscordDebug must be provided with a reference to the server.'
|
||||
);
|
||||
if (!server) throw new Error('DiscordDebug must be provided with a reference to the server.');
|
||||
|
||||
if (!discordClient)
|
||||
throw new Error('DiscordDebug must be provided with a Discord.js client.');
|
||||
if (!discordClient) throw new Error('DiscordDebug must be provided with a Discord.js client.');
|
||||
|
||||
options = {
|
||||
color: 16761867,
|
||||
@ -87,8 +80,7 @@ export default async function(server, discordClient, options = {}) {
|
||||
// confirm it's a status message
|
||||
if (
|
||||
reaction.message.embeds.length !== 1 ||
|
||||
reaction.message.embeds[0].footer.text !==
|
||||
`Server Status by ${COPYRIGHT_MESSAGE}`
|
||||
reaction.message.embeds[0].footer.text !== `Server Status by ${COPYRIGHT_MESSAGE}`
|
||||
)
|
||||
return;
|
||||
|
||||
|
@ -2,18 +2,11 @@ import { COPYRIGHT_MESSAGE } from 'core/config';
|
||||
import { LOG_PARSER_TEAMKILL } from 'squad-server/events/log-parser';
|
||||
|
||||
export default async function(server, discordClient, channelID, options = {}) {
|
||||
if (!server)
|
||||
throw new Error(
|
||||
'DiscordTeamKill must be provided with a reference to the server.'
|
||||
);
|
||||
if (!server) throw new Error('DiscordTeamKill must be provided with a reference to the server.');
|
||||
|
||||
if (!discordClient)
|
||||
throw new Error(
|
||||
'DiscordTeamkill must be provided with a Discord.js client.'
|
||||
);
|
||||
if (!discordClient) throw new Error('DiscordTeamkill must be provided with a Discord.js client.');
|
||||
|
||||
if (!channelID)
|
||||
throw new Error('DiscordTeamkill must be provided with a channel ID.');
|
||||
if (!channelID) throw new Error('DiscordTeamkill must be provided with a channel ID.');
|
||||
|
||||
options = {
|
||||
teamkillColor: 16761867,
|
||||
@ -64,9 +57,7 @@ export default async function(server, discordClient, channelID, options = {}) {
|
||||
|
||||
channel.send({
|
||||
embed: {
|
||||
title: `${info.suicide ? 'Suicide' : 'Teamkill'}: ${
|
||||
info.attacker.name
|
||||
}`,
|
||||
title: `${info.suicide ? 'Suicide' : 'Teamkill'}: ${info.attacker.name}`,
|
||||
color: info.suicide ? options.suicideColor : options.teamkillColor,
|
||||
fields: fields,
|
||||
timestamp: info.time.toISOString(),
|
||||
|
@ -9,13 +9,9 @@ import {
|
||||
import { SERVER_PLAYERS_UPDATED } from 'squad-server/events/server';
|
||||
|
||||
export default function(server, influxDB, options = {}) {
|
||||
if (!server)
|
||||
throw new Error(
|
||||
'InfluxDBLog must be provided with a reference to the server.'
|
||||
);
|
||||
if (!server) throw new Error('InfluxDBLog must be provided with a reference to the server.');
|
||||
|
||||
if (!influxDB)
|
||||
throw new Error('InfluxDBLog must be provided with a InfluxDB connection.');
|
||||
if (!influxDB) throw new Error('InfluxDBLog must be provided with a InfluxDB connection.');
|
||||
|
||||
const serverID = options.overrideServerID || server.id;
|
||||
|
||||
|
@ -37,7 +37,20 @@ const activeLayerFilter = {
|
||||
Invasion: 4 // invasion can only be played once every x layers
|
||||
// if not specified they will default to off
|
||||
},
|
||||
playerCountComplianceEnabled: true // filter layers based on suggested player counts if true
|
||||
gamemodeRepetitiveTolerance: {
|
||||
Invasion: 4 // invasion can only be played up to x times in a row
|
||||
// if not specified they will default to off
|
||||
},
|
||||
playerCountComplianceEnabled: true, // filter layers based on suggested player counts if true
|
||||
factionComplianceEnabled: true, // a team cannot play the same faction twice in a row
|
||||
factionHistoryTolerance: {
|
||||
RUS: 4 // rus can only be played once every x layers
|
||||
// if not specified they will default to off
|
||||
},
|
||||
factionRepetitiveTolerance: {
|
||||
RUS: 4 // rus can only be played up to x times in a row
|
||||
// if not specified they will default to off
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
|
@ -22,10 +22,7 @@ export default function(server, options = {}) {
|
||||
if (voteMatch) {
|
||||
if (!mapvote) return;
|
||||
try {
|
||||
const layerName = await mapvote.makeVoteByNumber(
|
||||
info.steamID,
|
||||
parseInt(voteMatch[1])
|
||||
);
|
||||
const layerName = await mapvote.makeVoteByNumber(info.steamID, parseInt(voteMatch[1]));
|
||||
await server.rcon.warn(info.steamID, `You voted for ${layerName}.`);
|
||||
} catch (err) {
|
||||
await server.rcon.warn(info.steamID, err.message);
|
||||
@ -93,10 +90,7 @@ export default function(server, options = {}) {
|
||||
|
||||
if (results.length === 0)
|
||||
await server.rcon.broadcast(`No layer gained enough votes to win.`);
|
||||
else
|
||||
await server.rcon.broadcast(
|
||||
`${mapvote.getResults()[0].layer.layer} won the mapvote!`
|
||||
);
|
||||
else await server.rcon.broadcast(`${mapvote.getResults()[0].layer.layer} won the mapvote!`);
|
||||
|
||||
mapvote = null;
|
||||
return;
|
||||
@ -109,15 +103,9 @@ export default function(server, options = {}) {
|
||||
}
|
||||
|
||||
if (commandMatch[1] === 'help') {
|
||||
await server.rcon.warn(
|
||||
info.steamID,
|
||||
'To vote type the layer number into chat:'
|
||||
);
|
||||
await server.rcon.warn(info.steamID, 'To vote type the layer number into chat:');
|
||||
for (const layer of mapvote.squadLayerFilter.getLayers()) {
|
||||
await server.rcon.warn(
|
||||
info.steamID,
|
||||
`${layer.layerNumber} - ${layer.layer}`
|
||||
);
|
||||
await server.rcon.warn(info.steamID, `${layer.layerNumber} - ${layer.layer}`);
|
||||
}
|
||||
|
||||
if (options.minVoteCount !== null)
|
||||
@ -138,16 +126,13 @@ export default function(server, options = {}) {
|
||||
if (results.length === 0) {
|
||||
await server.rcon.warn(info.steamID, 'No one has voted yet.');
|
||||
} else {
|
||||
await server.rcon.warn(
|
||||
info.steamID,
|
||||
'The current vote counts are as follows:'
|
||||
);
|
||||
await server.rcon.warn(info.steamID, 'The current vote counts are as follows:');
|
||||
for (const result of results) {
|
||||
await server.rcon.warn(
|
||||
info.steamID,
|
||||
`${result.layer.layerNumber} - ${result.layer.layer} (${
|
||||
result.votes
|
||||
} vote${result.votes > 1 ? 's' : ''})`
|
||||
`${result.layer.layerNumber} - ${result.layer.layer} (${result.votes} vote${
|
||||
result.votes > 1 ? 's' : ''
|
||||
})`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -49,18 +49,9 @@ export default function(server, squadLayerFilter, options = {}) {
|
||||
if (!match) return;
|
||||
|
||||
if (match[1] === 'help') {
|
||||
await server.rcon.warn(
|
||||
info.steamID,
|
||||
'You may use any of the following commands in chat:'
|
||||
);
|
||||
await server.rcon.warn(
|
||||
info.steamID,
|
||||
'!mapvote results - View the current vote counts.'
|
||||
);
|
||||
await server.rcon.warn(
|
||||
info.steamID,
|
||||
'!mapvote <layer name> - Vote for the specified layer.'
|
||||
);
|
||||
await server.rcon.warn(info.steamID, 'You may use any of the following commands in chat:');
|
||||
await server.rcon.warn(info.steamID, '!mapvote results - View the current vote counts.');
|
||||
await server.rcon.warn(info.steamID, '!mapvote <layer name> - Vote for the specified layer.');
|
||||
await server.rcon.warn(
|
||||
info.steamID,
|
||||
'When inputting a layer name, we autocorrect any miss spelling.'
|
||||
@ -102,12 +93,8 @@ export default function(server, squadLayerFilter, options = {}) {
|
||||
|
||||
const results = mapvote.getResults(true);
|
||||
|
||||
if (results.length === 0)
|
||||
await server.rcon.broadcast(`No layer gained enough votes to win.`);
|
||||
else
|
||||
await server.rcon.broadcast(
|
||||
`${mapvote.getResults()[0].layer.layer} won the mapvote!`
|
||||
);
|
||||
if (results.length === 0) await server.rcon.broadcast(`No layer gained enough votes to win.`);
|
||||
else await server.rcon.broadcast(`${mapvote.getResults()[0].layer.layer} won the mapvote!`);
|
||||
|
||||
mapvote = null;
|
||||
return;
|
||||
@ -125,16 +112,11 @@ export default function(server, squadLayerFilter, options = {}) {
|
||||
if (results.length === 0) {
|
||||
await server.rcon.warn(info.steamID, 'No one has voted yet.');
|
||||
} else {
|
||||
await server.rcon.warn(
|
||||
info.steamID,
|
||||
'The current vote counts are as follows:'
|
||||
);
|
||||
await server.rcon.warn(info.steamID, 'The current vote counts are as follows:');
|
||||
for (const result of results) {
|
||||
await server.rcon.warn(
|
||||
info.steamID,
|
||||
`${result.layer.layer} - ${result.votes} vote${
|
||||
result.votes > 1 ? 's' : ''
|
||||
}`
|
||||
`${result.layer.layer} - ${result.votes} vote${result.votes > 1 ? 's' : ''}`
|
||||
);
|
||||
}
|
||||
return;
|
||||
@ -142,18 +124,12 @@ export default function(server, squadLayerFilter, options = {}) {
|
||||
}
|
||||
|
||||
if (!manuallyCreated && server.players.length < options.minPlayerCount) {
|
||||
await server.rcon.warn(
|
||||
info.steamID,
|
||||
'Not enough players online to vote.'
|
||||
);
|
||||
await server.rcon.warn(info.steamID, 'Not enough players online to vote.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const layerName = await mapvote.makeVoteByDidYouMean(
|
||||
info.steamID,
|
||||
match[1]
|
||||
);
|
||||
const layerName = await mapvote.makeVoteByDidYouMean(info.steamID, match[1]);
|
||||
await server.rcon.warn(info.steamID, `You voted for ${layerName}.`);
|
||||
} catch (err) {
|
||||
await server.rcon.warn(info.steamID, err.message);
|
||||
|
@ -9,6 +9,7 @@ export default class MapVote extends EventEmitter {
|
||||
this.squadLayerFilter = squadLayerFilter;
|
||||
|
||||
this.layerVotes = {};
|
||||
this.layerVoteTimes = {};
|
||||
this.playerVotes = {};
|
||||
this.currentWinner = null;
|
||||
|
||||
@ -20,6 +21,7 @@ export default class MapVote extends EventEmitter {
|
||||
this.layerVotes[layerName] += 1;
|
||||
} else {
|
||||
this.layerVotes[layerName] = 1;
|
||||
this.layerVoteTimes[layerName] = new Date();
|
||||
}
|
||||
this.playerVotes[identifier] = layerName;
|
||||
}
|
||||
@ -29,8 +31,11 @@ export default class MapVote extends EventEmitter {
|
||||
|
||||
if (this.layerVotes[this.playerVotes[identifier]])
|
||||
this.layerVotes[this.playerVotes[identifier]] -= 1;
|
||||
if (this.layerVotes[this.playerVotes[identifier]] === 0)
|
||||
|
||||
if (this.layerVotes[this.playerVotes[identifier]] === 0) {
|
||||
delete this.layerVotes[this.playerVotes[identifier]];
|
||||
delete this.layerVoteTimes[this.playerVotes[identifier]];
|
||||
}
|
||||
|
||||
delete this.playerVotes[identifier];
|
||||
}
|
||||
@ -49,7 +54,7 @@ export default class MapVote extends EventEmitter {
|
||||
.sort((a, b) => {
|
||||
if (a.votes > b.votes) return -1;
|
||||
if (a.votes < b.votes) return 1;
|
||||
else return Math.random() < 0.5 ? 1 : -1;
|
||||
return this.layerVoteTimes[a.layer.layer] < this.layerVoteTimes[b.layer.layer] ? -1 : 1;
|
||||
});
|
||||
} else return [];
|
||||
}
|
||||
@ -66,6 +71,18 @@ export default class MapVote extends EventEmitter {
|
||||
throw new Error(`${layer.map} was played too recently.`);
|
||||
if (!this.squadLayerFilter.isGamemodeHistoryCompliant(this.server, layer))
|
||||
throw new Error(`${layer.gamemode} was played too recently.`);
|
||||
if (!this.squadLayerFilter.isGamemodeRepetitiveCompliant(this.server, layer))
|
||||
throw new Error(`${layer.gamemode} has been played too much recently.`);
|
||||
if (!this.squadLayerFilter.isFactionCompliant(this.server, layer))
|
||||
throw new Error('Cannot be played as one team will remain the same faction.');
|
||||
if (!this.squadLayerFilter.isFactionHistoryCompliant(this.server, layer))
|
||||
throw new Error(
|
||||
`Cannot be played as either ${layer.teamOne.faction} or ${layer.teamTwo.faction} has been played too recently.`
|
||||
);
|
||||
if (!this.squadLayerFilter.isFactionRepetitiveCompliant(this.server, layer))
|
||||
throw new Error(
|
||||
`Cannot be played as either ${layer.teamOne.faction} or ${layer.teamTwo.faction} has been played too much recently.`
|
||||
);
|
||||
if (!this.squadLayerFilter.isPlayerCountCompliant(this.server, layer))
|
||||
throw new Error(
|
||||
`${layer.layer} is only suitable for a player count between ${layer.estimatedSuitablePlayerCount.min} and ${layer.estimatedSuitablePlayerCount.max}.`
|
||||
@ -77,12 +94,10 @@ export default class MapVote extends EventEmitter {
|
||||
const results = this.getResults(true);
|
||||
|
||||
if (results.length > 0) {
|
||||
if (results[0] !== this.currentWinner) {
|
||||
await this.server.rcon.execute(
|
||||
`AdminSetNextMap ${results[0].layer.layer}`
|
||||
);
|
||||
if (results[0].layer.layer !== this.currentWinner) {
|
||||
await this.server.rcon.execute(`AdminSetNextMap ${results[0].layer.layer}`);
|
||||
this.emit('NEW_WINNER', results);
|
||||
this.currentWinner = results[0];
|
||||
this.currentWinner = results[0].layer.layer;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,28 +8,25 @@ import {
|
||||
import { SERVER_PLAYERS_UPDATED } from 'squad-server/events/server';
|
||||
|
||||
export default function(server, mysqlPool, options = {}) {
|
||||
if (!server)
|
||||
throw new Error(
|
||||
'MySQLLog must be provided with a reference to the server.'
|
||||
);
|
||||
if (!server) throw new Error('MySQLLog must be provided with a reference to the server.');
|
||||
|
||||
if (!mysqlPool)
|
||||
throw new Error('MySQLLog must be provided with a mysql Pool.');
|
||||
if (!mysqlPool) throw new Error('MySQLLog must be provided with a mysql Pool.');
|
||||
|
||||
const serverID = options.overrideServerID || server.id;
|
||||
|
||||
server.on(LOG_PARSER_SERVER_TICK_RATE, info => {
|
||||
mysqlPool.query(
|
||||
'INSERT INTO ServerTickRate(time, server, tick_rate) VALUES (?,?,?)',
|
||||
[info.time, serverID, info.tickRate]
|
||||
);
|
||||
mysqlPool.query('INSERT INTO ServerTickRate(time, server, tick_rate) VALUES (?,?,?)', [
|
||||
info.time,
|
||||
serverID,
|
||||
info.tickRate
|
||||
]);
|
||||
});
|
||||
|
||||
server.on(SERVER_PLAYERS_UPDATED, players => {
|
||||
mysqlPool.query(
|
||||
'INSERT INTO PlayerCount(time, server, player_count) VALUES (NOW(),?,?)',
|
||||
[serverID, players.length]
|
||||
);
|
||||
mysqlPool.query('INSERT INTO PlayerCount(time, server, player_count) VALUES (NOW(),?,?)', [
|
||||
serverID,
|
||||
players.length
|
||||
]);
|
||||
});
|
||||
|
||||
server.on(LOG_PARSER_NEW_GAME, info => {
|
||||
@ -82,28 +79,25 @@ export default function(server, mysqlPool, options = {}) {
|
||||
});
|
||||
|
||||
server.on(LOG_PARSER_PLAYER_REVIVED, info => {
|
||||
mysqlPool.query(
|
||||
'call InsertPlayerRevived(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
|
||||
[
|
||||
serverID,
|
||||
info.time,
|
||||
info.woundTime,
|
||||
info.victim ? info.victim.steamID : null,
|
||||
info.victim ? info.victim.name : null,
|
||||
info.victim ? info.victim.teamID : null,
|
||||
info.victim ? info.victim.squadID : null,
|
||||
info.attacker ? info.attacker.steamID : null,
|
||||
info.attacker ? info.attacker.name : null,
|
||||
info.attacker ? info.attacker.teamID : null,
|
||||
info.attacker ? info.attacker.squadID : null,
|
||||
info.damage,
|
||||
info.weapon,
|
||||
info.teamkill,
|
||||
info.reviver ? info.reviver.steamID : null,
|
||||
info.reviver ? info.reviver.name : null,
|
||||
info.reviver ? info.reviver.teamID : null,
|
||||
info.reviver ? info.reviver.squadID : null
|
||||
]
|
||||
);
|
||||
mysqlPool.query('call InsertPlayerRevived(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)', [
|
||||
serverID,
|
||||
info.time,
|
||||
info.woundTime,
|
||||
info.victim ? info.victim.steamID : null,
|
||||
info.victim ? info.victim.name : null,
|
||||
info.victim ? info.victim.teamID : null,
|
||||
info.victim ? info.victim.squadID : null,
|
||||
info.attacker ? info.attacker.steamID : null,
|
||||
info.attacker ? info.attacker.name : null,
|
||||
info.attacker ? info.attacker.teamID : null,
|
||||
info.attacker ? info.attacker.squadID : null,
|
||||
info.damage,
|
||||
info.weapon,
|
||||
info.teamkill,
|
||||
info.reviver ? info.reviver.steamID : null,
|
||||
info.reviver ? info.reviver.name : null,
|
||||
info.reviver ? info.reviver.teamID : null,
|
||||
info.reviver ? info.reviver.squadID : null
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
@ -1,10 +1,7 @@
|
||||
import { LOG_PARSER_PLAYER_CONNECTED } from 'squad-server/events/log-parser';
|
||||
|
||||
export default function(server, options = {}) {
|
||||
if (!server)
|
||||
throw new Error(
|
||||
'SeedingMessage must be provided with a reference to the server.'
|
||||
);
|
||||
if (!server) throw new Error('SeedingMessage must be provided with a reference to the server.');
|
||||
|
||||
const mode = options.mode || 'interval';
|
||||
const interval = options.interval || 150 * 1000;
|
||||
|
@ -21,10 +21,7 @@ function shuffle(array) {
|
||||
}
|
||||
|
||||
export default function(server, options = {}) {
|
||||
if (!server)
|
||||
throw new Error(
|
||||
'TeamRandomizer must be provided with a reference to the server.'
|
||||
);
|
||||
if (!server) throw new Error('TeamRandomizer must be provided with a reference to the server.');
|
||||
|
||||
const command = options.command || '!randomize';
|
||||
const commandRegex = new RegExp(`^${command}`, 'i');
|
||||
|
@ -40,9 +40,4 @@ const SERVER_LAYERS_UPDATED = 'SERVER_LAYERS_UPDATED';
|
||||
*/
|
||||
const SERVER_A2S_UPDATED = 'SERVER_A2S_UPDATED';
|
||||
|
||||
export {
|
||||
SERVER_LAYER_CHANGE,
|
||||
SERVER_PLAYERS_UPDATED,
|
||||
SERVER_LAYERS_UPDATED,
|
||||
SERVER_A2S_UPDATED
|
||||
};
|
||||
export { SERVER_LAYER_CHANGE, SERVER_PLAYERS_UPDATED, SERVER_LAYERS_UPDATED, SERVER_A2S_UPDATED };
|
||||
|
@ -27,8 +27,7 @@ export default class Server extends EventEmitter {
|
||||
if (!('host' in options)) throw new Error('Server must have a host.');
|
||||
this.host = options.host;
|
||||
|
||||
if (!('queryPort' in options))
|
||||
throw new Error('Server must have a queryPort.');
|
||||
if (!('queryPort' in options)) throw new Error('Server must have a queryPort.');
|
||||
this.queryPort = options.queryPort;
|
||||
|
||||
this.updateInterval = options.updateInterval || 30 * 1000;
|
||||
@ -51,10 +50,7 @@ export default class Server extends EventEmitter {
|
||||
|
||||
// setup period updaters
|
||||
this.updatePlayers = this.updatePlayers.bind(this);
|
||||
this.updatePlayerTimeout = setTimeout(
|
||||
this.updatePlayers,
|
||||
this.updateInterval
|
||||
);
|
||||
this.updatePlayerTimeout = setTimeout(this.updatePlayers, this.updateInterval);
|
||||
|
||||
setInterval(async () => {
|
||||
const data = await this.rcon.getMapInfo();
|
||||
@ -121,10 +117,7 @@ export default class Server extends EventEmitter {
|
||||
}
|
||||
|
||||
// delay another update
|
||||
this.updatePlayerTimeout = setTimeout(
|
||||
this.updatePlayers,
|
||||
this.updateInterval
|
||||
);
|
||||
this.updatePlayerTimeout = setTimeout(this.updatePlayers, this.updateInterval);
|
||||
|
||||
this.emit(SERVER_PLAYERS_UPDATED, this.players);
|
||||
}
|
||||
|
@ -10,8 +10,7 @@ import rules from './rules/index.js';
|
||||
|
||||
export default class LogParser {
|
||||
constructor(options = {}, server) {
|
||||
if (!(server instanceof Server))
|
||||
throw new Error('Server not an instance of a SquadJS server.');
|
||||
if (!(server instanceof Server)) throw new Error('Server not an instance of a SquadJS server.');
|
||||
this.server = server;
|
||||
this.eventStore = {};
|
||||
|
||||
|
@ -10,13 +10,10 @@ import sleep from 'core/utils/sleep';
|
||||
export default class FTPLogReader {
|
||||
constructor(queueLine, options = {}) {
|
||||
if (typeof queueLine !== 'function')
|
||||
throw new Error(
|
||||
'queueLine argument must be specified and be a function.'
|
||||
);
|
||||
throw new Error('queueLine argument must be specified and be a function.');
|
||||
if (!options.host) throw new Error('Host must be specified.');
|
||||
if (!options.ftpUser) throw new Error('FTP user must be specified.');
|
||||
if (!options.ftpPassword)
|
||||
throw new Error('FTP password must be specified.');
|
||||
if (!options.ftpPassword) throw new Error('FTP password must be specified.');
|
||||
if (!options.remotePath) throw new Error('Remote path must be specified.');
|
||||
|
||||
this.queueLine = queueLine;
|
||||
@ -79,8 +76,7 @@ export default class FTPLogReader {
|
||||
if (this.lastByteReceived == null) {
|
||||
const fileSize = await this.client.size(this.remotePath);
|
||||
this.lastByteReceived =
|
||||
fileSize -
|
||||
(this.tailLastBytes < fileSize ? this.tailLastBytes : fileSize);
|
||||
fileSize - (this.tailLastBytes < fileSize ? this.tailLastBytes : fileSize);
|
||||
}
|
||||
|
||||
// Download the data to a temp file, overwrite any previous data
|
||||
|
@ -4,17 +4,12 @@ import TailModule from 'tail';
|
||||
export default class TailLogReader {
|
||||
constructor(queueLine, options = {}) {
|
||||
if (typeof queueLine !== 'function')
|
||||
throw new Error(
|
||||
'queueLine argument must be specified and be a function.'
|
||||
);
|
||||
throw new Error('queueLine argument must be specified and be a function.');
|
||||
if (!options.logDir) throw new Error('Log directory must be specified.');
|
||||
|
||||
this.reader = new TailModule.Tail(
|
||||
path.join(options.logDir, 'SquadGame.log'),
|
||||
{
|
||||
useWatchFile: true
|
||||
}
|
||||
);
|
||||
this.reader = new TailModule.Tail(path.join(options.logDir, 'SquadGame.log'), {
|
||||
useWatchFile: true
|
||||
});
|
||||
|
||||
this.reader.on('line', queueLine);
|
||||
}
|
||||
|
@ -3,8 +3,7 @@ import { LOG_PARSER_PLAYER_CONNECTED } from '../../events/log-parser.js';
|
||||
export default {
|
||||
regex: /^\[([0-9.:-]+)]\[([ 0-9]*)]LogNet: Join succeeded: (.+)/,
|
||||
onMatch: async (args, logParser) => {
|
||||
logParser.server.suffixStore[logParser.eventStore['steamid-connected']] =
|
||||
args[3];
|
||||
logParser.server.suffixStore[logParser.eventStore['steamid-connected']] = args[3];
|
||||
|
||||
const data = {
|
||||
raw: args[0],
|
||||
|
@ -11,10 +11,7 @@ export default {
|
||||
switchPossess: false
|
||||
};
|
||||
|
||||
if (
|
||||
args[3] in logParser.eventStore &&
|
||||
logParser.eventStore[args[3]] === args[2]
|
||||
)
|
||||
if (args[3] in logParser.eventStore && logParser.eventStore[args[3]] === args[2])
|
||||
data.switchPossess = true;
|
||||
delete logParser.eventStore[args[3]];
|
||||
|
||||
|
@ -1,7 +1,4 @@
|
||||
import {
|
||||
LOG_PARSER_PLAYER_WOUNDED,
|
||||
LOG_PARSER_TEAMKILL
|
||||
} from '../../events/log-parser.js';
|
||||
import { LOG_PARSER_PLAYER_WOUNDED, LOG_PARSER_TEAMKILL } from '../../events/log-parser.js';
|
||||
|
||||
export default {
|
||||
regex: /^\[([0-9.:-]+)]\[([ 0-9]*)]LogSquadTrace: \[DedicatedServer](?:ASQSoldier::)?Wound\(\): Player:(.+) KillingDamage=(?:-)*([0-9.]+) from ([A-z_0-9]+) caused by ([A-z_0-9]+)_C/,
|
||||
|
@ -48,9 +48,7 @@ async function main() {
|
||||
|
||||
console.log('Done.');
|
||||
console.log();
|
||||
console.log(
|
||||
`Matched ${matched} / ${total} (${(matched / total) * 100}%) log lines.`
|
||||
);
|
||||
console.log(`Matched ${matched} / ${total} (${(matched / total) * 100}%) log lines.`);
|
||||
console.log();
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,7 @@ export default class Rcon {
|
||||
if (!options.rconPort) throw new Error('RCON port must be specified.');
|
||||
this.port = options.rconPort;
|
||||
|
||||
if (!options.rconPassword)
|
||||
throw new Error('RCON password must be specified.');
|
||||
if (!options.rconPassword) throw new Error('RCON password must be specified.');
|
||||
this.password = options.rconPassword;
|
||||
|
||||
this.verboseEnabled = options.rconVerbose || false;
|
||||
@ -195,10 +194,7 @@ export default class Rcon {
|
||||
''
|
||||
);
|
||||
|
||||
if (
|
||||
this.maximumPacketSize > 0 &&
|
||||
encodedPacket.length > this.maximumPacketSize
|
||||
)
|
||||
if (this.maximumPacketSize > 0 && encodedPacket.length > this.maximumPacketSize)
|
||||
reject(new Error('Packet too long.'));
|
||||
|
||||
// prepare to handle response.
|
||||
@ -233,8 +229,7 @@ export default class Rcon {
|
||||
resolve(response);
|
||||
};
|
||||
|
||||
if (type === RCONProtocol.SERVERDATA_AUTH)
|
||||
this.requestQueue.push(handleAuthMultiPacket);
|
||||
if (type === RCONProtocol.SERVERDATA_AUTH) this.requestQueue.push(handleAuthMultiPacket);
|
||||
else this.requestQueue.push(handleMultiPacket);
|
||||
|
||||
this.client.once('error', reject);
|
||||
@ -311,7 +306,6 @@ export default class Rcon {
|
||||
}
|
||||
|
||||
verbose(msg) {
|
||||
if (this.verboseEnabled)
|
||||
console.log(`[${Date.now()}] RCON (Verbose): ${msg}`);
|
||||
if (this.verboseEnabled) console.log(`[${Date.now()}] RCON (Verbose): ${msg}`);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user