Skip to content

Commit

Permalink
Merge pull request #318 from fantinodavide/eos-integration
Browse files Browse the repository at this point in the history
EOS integration, major rewrite.
  • Loading branch information
werewolfboy13 committed Jan 5, 2024
2 parents bc8fb4c + 8fcce1a commit dffc8b6
Show file tree
Hide file tree
Showing 25 changed files with 561 additions and 160 deletions.
8 changes: 6 additions & 2 deletions core/log-parser/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@ export default class LogParser extends EventEmitter {

this.eventStore = {
disconnected: {}, // holding area, cleared on map change.
players: {}, // persistent data, steamid, controller, suffix.
players: [], // persistent data, steamid, controller, suffix.
playersEOS: [], // proxies from EOSID to persistent data, steamid, controller, suffix.
connectionIdToSteamID: new Map(),
session: {}, // old eventstore, nonpersistent data
clients: {} // used in the connection chain before we resolve a player.
clients: {}, // used in the connection chain before we resolve a player.
lastConnection: {}, // used to store the last client connection data to then associate a steamid
joinRequests: []
};

this.linesPerMinute = 0;
Expand Down
4 changes: 1 addition & 3 deletions core/rcon.js
Original file line number Diff line number Diff line change
Expand Up @@ -337,8 +337,7 @@ 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);
Expand All @@ -352,7 +351,6 @@ 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);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "SquadJS",
"version": "3.8.2",
"version": "4.0.0",
"repository": "https://github.com/Team-Silver-Sphere/SquadJS.git",
"author": "Thomas Smyth <https://github.com/Thomas-Smyth>",
"license": "BSL-1.0",
Expand Down
139 changes: 100 additions & 39 deletions squad-server/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import EventEmitter from 'events';

import axios from 'axios';
import Gamedig from 'gamedig';

import Logger from 'core/logger';
import { SQUADJS_API_DOMAIN } from 'core/constants';
Expand All @@ -19,7 +18,7 @@ export default class SquadServer extends EventEmitter {
constructor(options = {}) {
super();

for (const option of ['host', 'queryPort'])
for (const option of ['host'])
if (!(option in options)) throw new Error(`${option} must be specified.`);

this.id = options.id;
Expand Down Expand Up @@ -73,13 +72,13 @@ export default class SquadServer extends EventEmitter {
this.admins = await fetchAdminLists(this.options.adminLists);

await this.rcon.connect();
await this.logParser.watch();

await this.updateSquadList();
await this.updatePlayerList();
await this.updatePlayerList(this);
await this.updateLayerInformation();
await this.updateA2SInformation();

await this.logParser.watch();

Logger.verbose('SquadServer', 1, `Watching ${this.serverName}...`);

await this.pingSquadJSAPI();
Expand Down Expand Up @@ -154,9 +153,12 @@ export default class SquadServer extends EventEmitter {
});

this.rcon.on('SQUAD_CREATED', async (data) => {
data.player = await this.getPlayerBySteamID(data.playerSteamID, true);
data.player = await this.getPlayerByEOSID(data.playerEOSID, true);
data.player.squadID = data.squadID;

delete data.playerName;
delete data.playerSteamID;
delete data.playerEOSID;

this.emit('SQUAD_CREATED', data);
});
Expand Down Expand Up @@ -207,7 +209,13 @@ export default class SquadServer extends EventEmitter {
});

this.logParser.on('PLAYER_CONNECTED', async (data) => {
data.player = await this.getPlayerBySteamID(data.steamID);
Logger.verbose(
'SquadServer',
1,
`Player connected ${data.playerSuffix} - SteamID: ${data.steamID} - EOSID: ${data.eosID} - IP: ${data.ip}`
);

data.player = await this.getPlayerByEOSID(data.eosID);
if (data.player) data.player.suffix = data.playerSuffix;

delete data.steamID;
Expand All @@ -217,7 +225,7 @@ export default class SquadServer extends EventEmitter {
});

this.logParser.on('PLAYER_DISCONNECTED', async (data) => {
data.player = await this.getPlayerBySteamID(data.steamID);
data.player = await this.getPlayerByEOSID(data.eosID);

delete data.steamID;

Expand All @@ -226,12 +234,16 @@ export default class SquadServer extends EventEmitter {

this.logParser.on('PLAYER_DAMAGED', async (data) => {
data.victim = await this.getPlayerByName(data.victimName);
data.attacker = await this.getPlayerByName(data.attackerName);
data.attacker = await this.getPlayerByEOSID(data.attackerEOSID);

if (data.victim && data.attacker)
if (data.attacker && !data.attacker.playercontroller && data.attackerController)
data.attacker.playercontroller = data.attackerController;

if (data.victim && data.attacker) {
data.teamkill =
data.victim.teamID === data.attacker.teamID &&
data.victim.steamID !== data.attacker.steamID;
}

delete data.victimName;
delete data.attackerName;
Expand All @@ -241,7 +253,7 @@ 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);
data.attacker = await this.getPlayerByEOSID(data.attackerEOSID);
if (!data.attacker)
data.attacker = await this.getPlayerByController(data.attackerPlayerController);

Expand All @@ -259,7 +271,7 @@ 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);
data.attacker = await this.getPlayerByEOSID(data.attackerEOSID);
if (!data.attacker)
data.attacker = await this.getPlayerByController(data.attackerPlayerController);

Expand All @@ -275,9 +287,9 @@ export default class SquadServer extends EventEmitter {
});

this.logParser.on('PLAYER_REVIVED', async (data) => {
data.victim = await this.getPlayerByName(data.victimName);
data.attacker = await this.getPlayerByName(data.attackerName);
data.reviver = await this.getPlayerByName(data.reviverName);
data.victim = await this.getPlayerByEOSID(data.victimEOSID);
data.attacker = await this.getPlayerByEOSID(data.attackerEOSID);
data.reviver = await this.getPlayerByEOSID(data.reviverEOSID);

delete data.victimName;
delete data.attackerName;
Expand All @@ -287,7 +299,7 @@ export default class SquadServer extends EventEmitter {
});

this.logParser.on('PLAYER_POSSESS', async (data) => {
data.player = await this.getPlayerByNameSuffix(data.playerSuffix);
data.player = await this.getPlayerByEOSID(data.playerEOSID);
if (data.player) data.player.possessClassname = data.possessClassname;

delete data.playerSuffix;
Expand All @@ -296,7 +308,7 @@ export default class SquadServer extends EventEmitter {
});

this.logParser.on('PLAYER_UNPOSSESS', async (data) => {
data.player = await this.getPlayerByNameSuffix(data.playerSuffix);
data.player = await this.getPlayerByEOSID(data.playerEOSID);

delete data.playerSuffix;

Expand All @@ -310,6 +322,23 @@ export default class SquadServer extends EventEmitter {
this.logParser.on('TICK_RATE', (data) => {
this.emit('TICK_RATE', data);
});

this.logParser.on('CLIENT_EXTERNAL_ACCOUNT_INFO', (data) => {
this.rcon.addIds(data.steamID, data.eosID);
});
// this.logParser.on('CLIENT_CONNECTED', (data) => {
// Logger.verbose("SquadServer", 1, `Client connected. Connection: ${data.connection} - SteamID: ${data.steamID}`)
// })
// this.logParser.on('CLIENT_LOGIN_REQUEST', (data) => {
// Logger.verbose("SquadServer", 1, `Login request. ChainID: ${data.chainID} - Suffix: ${data.suffix} - EOSID: ${data.eosID}`)

// })
// this.logParser.on('RESOLVED_EOS_ID', (data) => {
// Logger.verbose("SquadServer", 1, `Resolved EOSID. ChainID: ${data.chainID} - Suffix: ${data.suffix} - EOSID: ${data.eosID}`)
// })
// this.logParser.on('ADDING_CLIENT_CONNECTION', (data) => {
// Logger.verbose("SquadServer", 1, `Adding client connection`, data)
// })
}

async restartLogParser() {
Expand Down Expand Up @@ -352,7 +381,7 @@ export default class SquadServer extends EventEmitter {
}

const players = [];
for (const player of await this.rcon.getListPlayers())
for (const player of await this.rcon.getListPlayers(this))
players.push({
...oldPlayerInfo[player.steamID],
...player,
Expand Down Expand Up @@ -380,6 +409,13 @@ export default class SquadServer extends EventEmitter {
});
}

if (this.a2sPlayerCount > 0 && players.length === 0)
Logger.verbose(
'SquadServer',
1,
`Real Player Count: ${this.a2sPlayerCount} but loaded ${players.length}`
);

this.emit('UPDATED_PLAYER_INFORMATION');
} catch (err) {
Logger.verbose('SquadServer', 1, 'Failed to update player list.', err);
Expand Down Expand Up @@ -441,53 +477,70 @@ export default class SquadServer extends EventEmitter {
);
}

async updateA2SInformation() {
updateA2SInformation() {
return this.updateServerInformation();
}

async updateServerInformation() {
if (this.updateA2SInformationTimeout) clearTimeout(this.updateA2SInformationTimeout);

Logger.verbose('SquadServer', 1, `Updating A2S information...`);
Logger.verbose('SquadServer', 1, `Updating server information...`);

try {
const data = await Gamedig.query({
type: 'squad',
host: this.options.host,
port: this.options.queryPort
});
const rawData = await this.rcon.execute(`ShowServerInfo`);
Logger.verbose('SquadServer', 3, `Server information raw data`, rawData);
const data = JSON.parse(rawData);
Logger.verbose('SquadServer', 2, `Server information data`, JSON.data);

const info = {
raw: data.raw,
serverName: data.name,
raw: data,
serverName: data.ServerName_s,

maxPlayers: parseInt(data.MaxPlayers),
publicQueueLimit: parseInt(data.PublicQueueLimit_I),
reserveSlots: parseInt(data.PlayerReserveCount_I),

maxPlayers: parseInt(data.maxplayers),
publicSlots: parseInt(data.raw.rules.NUMPUBCONN),
reserveSlots: parseInt(data.raw.rules.NUMPRIVCONN),
playerCount: parseInt(data.PlayerCount_I),
a2sPlayerCount: parseInt(data.PlayerCount_I),
publicQueue: parseInt(data.PublicQueue_I),
reserveQueue: parseInt(data.ReservedQueue_I),

a2sPlayerCount: parseInt(data.raw.rules.PlayerCount_i),
publicQueue: parseInt(data.raw.rules.PublicQueue_i),
reserveQueue: parseInt(data.raw.rules.ReservedQueue_i),
currentLayer: data.MapName_s,
nextLayer: data.NextLayer_s,

matchTimeout: parseFloat(data.raw.rules.MatchTimeout_f),
gameVersion: data.raw.version
teamOne: data.TeamOne_s?.replace(new RegExp(data.MapName_s, 'i'), '') || '',
teamTwo: data.TeamTwo_s?.replace(new RegExp(data.MapName_s, 'i'), '') || '',

matchTimeout: parseFloat(data.MatchTimeout_d),
matchStartTime: this.getMatchStartTimeByPlaytime(data.PLAYTIME_I),
gameVersion: data.GameVersion_s
};

this.serverName = info.serverName;

this.maxPlayers = info.maxPlayers;
this.publicSlots = info.publicSlots;
this.publicSlots = info.maxPlayers - info.reserveSlots;
this.reserveSlots = info.reserveSlots;

this.a2sPlayerCount = info.a2sPlayerCount;
this.a2sPlayerCount = info.playerCount;
this.playerCount = info.playerCount;
this.publicQueue = info.publicQueue;
this.reserveQueue = info.reserveQueue;

this.matchTimeout = info.matchTimeout;
this.matchStartTime = info.matchStartTime;
this.gameVersion = info.gameVersion;

if (!this.currentLayer) this.currentLayer = Layers.getLayerByClassname(info.currentLayer);
if (!this.nextLayer) this.nextLayer = Layers.getLayerByClassname(info.nextLayer);

this.emit('UPDATED_A2S_INFORMATION', info);
this.emit('UPDATED_SERVER_INFORMATION', info);
} catch (err) {
Logger.verbose('SquadServer', 1, 'Failed to update A2S information.', err);
Logger.verbose('SquadServer', 1, 'Failed to update server information.', err);
}

Logger.verbose('SquadServer', 1, `Updated A2S information.`);
Logger.verbose('SquadServer', 1, `Updated server information.`);

this.updateA2SInformationTimeout = setTimeout(
this.updateA2SInformation,
Expand Down Expand Up @@ -542,6 +595,10 @@ export default class SquadServer extends EventEmitter {
return this.getPlayerByCondition((player) => player.steamID === steamID, forceUpdate);
}

async getPlayerByEOSID(eosID, forceUpdate) {
return this.getPlayerByCondition((player) => player.eosID === eosID, forceUpdate);
}

async getPlayerByName(name, forceUpdate) {
return this.getPlayerByCondition((player) => player.name === name, forceUpdate);
}
Expand Down Expand Up @@ -606,4 +663,8 @@ export default class SquadServer extends EventEmitter {

this.pingSquadJSAPITimeout = setTimeout(this.pingSquadJSAPI, this.pingSquadJSAPIInterval);
}

getMatchStartTimeByPlaytime(playtime) {
return new Date(Date.now() - +playtime * 1000);
}
}
20 changes: 20 additions & 0 deletions squad-server/log-parser/adding-client-connection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export default {
regex:
/^\[([0-9.:-]+)]\[([ 0-9]*)]LogNet: AddClientConnection: Added client connection: \[UNetConnection\] RemoteAddr: ([\d.]+):[0-9]+, Name: (EOSIpNetConnection_[0-9]+), Driver: GameNetDriver (EOSNetDriver_[0-9]+), IsServer: YES, PC: NULL, Owner: NULL, UniqueId: INVALID/,
onMatch: (args, logParser) => {
const data = {
raw: args[0],
time: args[1],
chainID: args[2],
// steamID: args[ 3 ],
ip: args[3],
connection: args[4],
driver: args[5]
};
/* This is Called when unreal engine adds a client connection
First Step in Adding a Player to server
*/
logParser.eventStore['last-connection'] = data;
logParser.emit('ADDING_CLIENT_CONNECTION', data);
}
};
15 changes: 15 additions & 0 deletions squad-server/log-parser/check-permission-resolve-eosid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export default {
regex:
/^\[([0-9.:-]+)]\[([ 0-9]*)]LogSquadCommon: SQCommonStatics Check Permissions, UniqueId:([\da-f]+)$/,
onMatch: (args, logParser) => {
const data = {
raw: args[0],
time: args[1],
chainID: +args[2],
eosID: args[3]
};

logParser.eventStore.joinRequests[data.chainID].eosID = data.eosID;
logParser.emit('RESOLVED_EOS_ID', { ...logParser.eventStore.joinRequests[data.chainID] });
}
};
21 changes: 21 additions & 0 deletions squad-server/log-parser/client-external-account-info.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export default {
regex:
/^\[([0-9.:-]+)]\[([ 0-9]+)]LogEOS: Verbose: \[LogEOSConnect] FConnectClient::CacheExternalAccountInfo - ProductUserId: (?<eosId>[0-9a-f]{32}), AccountType: (\d), AccountId: (?<steamId>[0-9]{17}), DisplayName: <Redacted>/,
onMatch: (args, logParser) => {
const data = {
raw: args[0],
time: args[1],
chainID: args[2],
eosID: args.groups.eosId,
steamID: args.groups.steamId
};

logParser.eventStore.players[data.steamID] = {
eosID: data.eosID,
steamID: data.steamID
};
logParser.eventStore.playersEOS[data.eosID] = logParser.eventStore.players[data.steamID];

logParser.emit('CLIENT_EXTERNAL_ACCOUNT_INFO', data);
}
};
Loading

0 comments on commit dffc8b6

Please sign in to comment.