173 lines
5.5 KiB
TypeScript
173 lines
5.5 KiB
TypeScript
/*
|
|
* Copyright (C) 2025 Aleksander <alekswilc> Wilczyński (aleks@alekswilc.dev)
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published
|
|
* by the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* See LICENSE for more.
|
|
*/
|
|
|
|
import { IPlayerPayload, IPlayerStatsPayload } from "../types/player.js";
|
|
import { MProfile } from "../mongo/profile.js";
|
|
import { assert } from "node:console";
|
|
|
|
const steamKeys: string[] = JSON.parse(process.env.STEAM_APIKEY!);
|
|
|
|
const steamFetch = (url: string) =>
|
|
{
|
|
let retries = 0;
|
|
|
|
return new Promise((res, _rej) =>
|
|
{
|
|
const req = () =>
|
|
{
|
|
const steamKey = steamKeys[ Math.floor(Math.random() * steamKeys.length) ];
|
|
|
|
fetch(url.replace("[STEAMKEY]", steamKey), { signal: AbortSignal.timeout(10000) }).then(x => x.json())
|
|
.then(x => res(x))
|
|
.catch(() =>
|
|
{
|
|
console.log("STEAM request failed! ", url.replace("[STEAMKEY]", steamKey), retries);
|
|
|
|
retries++;
|
|
setTimeout(() => req(), retries * 1000);
|
|
});
|
|
};
|
|
req();
|
|
});
|
|
};
|
|
|
|
|
|
export class PlayerUtil
|
|
{
|
|
public static async ensurePlayer(steamId: number | string)
|
|
{
|
|
assert(steamId, "expected steamId to be a string or a number");
|
|
steamId = steamId.toString();
|
|
let player = await MProfile.findOne({ id: steamId });
|
|
|
|
if (!player)
|
|
{
|
|
const data = await steamFetch(`https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v2/?key=[STEAMKEY]&format=json&steamids=${ steamId }`) as IPlayerPayload;
|
|
|
|
assert(data.response.players, "Expected data.response.players to be truthy");
|
|
|
|
const stats = await this.getPlayerStats(steamId);
|
|
|
|
player = await MProfile.findOne({ id: steamId });
|
|
if (player)
|
|
{
|
|
return player;
|
|
}
|
|
|
|
const trainStats: {
|
|
[ trainName: string ]: {
|
|
score: number,
|
|
distance: number
|
|
time: number,
|
|
}
|
|
} = {};
|
|
const dispatcherStats: {
|
|
[ name: string ]: {
|
|
time: number
|
|
}
|
|
} = {};
|
|
|
|
let trainPoints = 0;
|
|
let trainDistance = 0;
|
|
let dispatcherTime = 0;
|
|
|
|
if (stats)
|
|
{
|
|
trainStats[ "N/A" ] = {
|
|
score: stats?.stats?.find(x => x.name === "SCORE")?.value ?? 0,
|
|
distance: stats?.stats?.find(x => x.name === "DISTANCE_M")?.value ?? 0,
|
|
time: 0,
|
|
};
|
|
|
|
dispatcherStats[ "N/A" ] = {
|
|
time: (stats?.stats?.find(x => x.name === "DISPATCHER_TIME")?.value ?? 0) * 1000 * 60,
|
|
};
|
|
|
|
trainPoints = stats?.stats?.find(x => x.name === "SCORE")?.value ?? 0;
|
|
trainDistance = stats?.stats?.find(x => x.name === "DISTANCE_M")?.value ?? 0;
|
|
dispatcherTime = (stats?.stats?.find(x => x.name === "DISPATCHER_TIME")?.value ?? 0) * 1000 * 60;
|
|
}
|
|
|
|
player = await MProfile.create({
|
|
id: steamId,
|
|
username: data.response.players[ 0 ].personaname,
|
|
avatar: data.response.players[ 0 ].avatarfull,
|
|
|
|
steamDispatcherTime: stats?.stats?.find(x => x.name === "DISPATCHER_TIME")?.value ?? 0,
|
|
steamTrainScore: stats?.stats?.find(x => x.name === "SCORE")?.value ?? 0,
|
|
steamTrainDistance: stats?.stats?.find(x => x.name === "DISTANCE_M")?.value ?? 0,
|
|
|
|
trainStats,
|
|
dispatcherStats,
|
|
|
|
trainPoints,
|
|
trainDistance,
|
|
trainTime: 0,
|
|
|
|
dispatcherTime,
|
|
|
|
flags: !stats ? [ "private" ] : [],
|
|
|
|
createdAt: Date.now(),
|
|
}).catch(e => e);
|
|
|
|
if (player instanceof Error)
|
|
{
|
|
player = await MProfile.findOne({ id: steamId });
|
|
}
|
|
|
|
}
|
|
|
|
assert(player, "expected player to be truthy");
|
|
|
|
return player;
|
|
}
|
|
|
|
public static async getPlayer(steamId: string)
|
|
{
|
|
const player = await MProfile.findOne({ id: steamId });
|
|
|
|
if (!player)
|
|
{
|
|
return undefined;
|
|
}
|
|
|
|
return player;
|
|
}
|
|
|
|
public static async getPlayerSteamData(steamId: string)
|
|
{
|
|
const data = await steamFetch(`https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v2/?key=[STEAMKEY]&format=json&steamids=${ steamId }`) as IPlayerPayload;
|
|
|
|
if (!data?.response?.players?.length)
|
|
{
|
|
return undefined;
|
|
}
|
|
|
|
return data.response.players[ 0 ];
|
|
}
|
|
|
|
public static async getPlayerStats(steamId: string)
|
|
{
|
|
const data = await steamFetch(`https://api.steampowered.com/ISteamUserStats/GetUserStatsForGame/v0002/?appid=1422130&key=[STEAMKEY]&steamid=${ steamId }`) as IPlayerStatsPayload;
|
|
|
|
if (!data.playerstats?.stats)
|
|
{
|
|
return undefined;
|
|
}
|
|
return data.playerstats;
|
|
}
|
|
} |