forked from simrail/simrail.pro
Merge pull request 'v2' (#19) from v2 into main
Reviewed-on: alekswilc/simrail-logs#19 Reviewed-by: Aleksander Wilczyński <aleks@alekswilc.dev>
This commit is contained in:
commit
dcb351796a
15
package-lock.json
generated
15
package-lock.json
generated
@ -1,13 +1,12 @@
|
||||
{
|
||||
"name": "play-history",
|
||||
"name": "simrail-logs",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "play-history",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"name": "simrail-logs",
|
||||
"license": "AGPL-3.0-only",
|
||||
"dependencies": {
|
||||
"@simrail/types": "^0.0.4",
|
||||
"@types/mongoose": "^5.11.97",
|
||||
@ -16,7 +15,8 @@
|
||||
"express": "^4.19.2",
|
||||
"mongoose": "^8.5.1",
|
||||
"redis": "^4.6.15",
|
||||
"uuid": "^10.0.0"
|
||||
"uuid": "^10.0.0",
|
||||
"wildcard-match": "^5.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.21",
|
||||
@ -1598,6 +1598,11 @@
|
||||
"node": ">=16"
|
||||
}
|
||||
},
|
||||
"node_modules/wildcard-match": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/wildcard-match/-/wildcard-match-5.1.3.tgz",
|
||||
"integrity": "sha512-a95hPUk+BNzSGLntNXYxsjz2Hooi5oL7xOfJR6CKwSsSALh7vUNuTlzsrZowtYy38JNduYFRVhFv19ocqNOZlg=="
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
|
@ -24,7 +24,8 @@
|
||||
"express": "^4.19.2",
|
||||
"mongoose": "^8.5.1",
|
||||
"redis": "^4.6.15",
|
||||
"uuid": "^10.0.0"
|
||||
"uuid": "^10.0.0",
|
||||
"wildcard-match": "^5.1.3"
|
||||
},
|
||||
"typings": "types/typings.d.ts"
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ https://simrail.alekswilc.dev/
|
||||
- Statystyki
|
||||
|
||||
## Dalszy rozwój
|
||||
- Obsługa pociagów, a nie tylko posterunków ([#8](https://git.alekswilc.dev/alekswilc/simrail-logs/issues/8))
|
||||
- Nowy wygląd aplikacji
|
||||
|
||||
# Zgłaszanie błedów
|
||||
Jak zgłosić błąd?
|
||||
|
10
scripts/clear-redis.js
Normal file
10
scripts/clear-redis.js
Normal file
@ -0,0 +1,10 @@
|
||||
import { createClient } from 'redis';
|
||||
|
||||
createClient({url: process.env.REDIS_URI}).connect().then(async (x) => {
|
||||
await x.json.del('stations_occupied');
|
||||
await x.json.del('stations');
|
||||
await x.json.del('trains');
|
||||
await x.json.del('trains_occupied');
|
||||
console.log('done')
|
||||
process.exit(1);
|
||||
})
|
81
src/http/routes/leaderboard.ts
Normal file
81
src/http/routes/leaderboard.ts
Normal file
@ -0,0 +1,81 @@
|
||||
import { Router } from 'express';
|
||||
import dayjs from 'dayjs';
|
||||
import { PlayerUtil } from '../../util/PlayerUtil.js';
|
||||
import { msToTime } from '../../util/time.js';
|
||||
|
||||
import { PipelineStage } from 'mongoose';
|
||||
import { MProfile, raw_schema } from '../../mongo/profile.js';
|
||||
|
||||
const generateSearch = (regex: RegExp) => [
|
||||
{
|
||||
steam: { $regex: regex },
|
||||
},
|
||||
{
|
||||
steamName: { $regex: regex },
|
||||
},
|
||||
]
|
||||
|
||||
export class LeaderboardRoute {
|
||||
static load() {
|
||||
const app = Router();
|
||||
|
||||
app.get('/train', async (req, res) => {
|
||||
const s = req.query.q?.toString().split(',').map(x => new RegExp(x, "i"));
|
||||
|
||||
const filter: PipelineStage[] = [];
|
||||
|
||||
|
||||
s && filter.push({
|
||||
$match: {
|
||||
$and: [
|
||||
...s.map(x => ({ $or: generateSearch(x) }))
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const records = await MProfile.aggregate(filter)
|
||||
.sort({ trainPoints: -1 })
|
||||
.limit(10)
|
||||
res.render('leaderboard/index.ejs', {
|
||||
records,
|
||||
dayjs,
|
||||
msToTime,
|
||||
type: 'train',
|
||||
q: req.query.q,
|
||||
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
app.get('/station', async (req, res) => {
|
||||
const s = req.query.q?.toString().split(',').map(x => new RegExp(x, "i"));
|
||||
|
||||
const filter: PipelineStage[] = [];
|
||||
|
||||
|
||||
s && filter.push({
|
||||
$match: {
|
||||
$and: [
|
||||
...s.map(x => ({ $or: generateSearch(x) }))
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const records = await MProfile.aggregate(filter)
|
||||
.sort({ dispatcherTime: -1 })
|
||||
.limit(10)
|
||||
res.render('leaderboard/index.ejs', {
|
||||
records,
|
||||
dayjs,
|
||||
msToTime,
|
||||
type: 'station',
|
||||
q: req.query.q,
|
||||
|
||||
});
|
||||
})
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
32
src/http/routes/profile.ts
Normal file
32
src/http/routes/profile.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { Router } from 'express';
|
||||
import dayjs from 'dayjs';
|
||||
import { PlayerUtil } from '../../util/PlayerUtil.js';
|
||||
import { msToTime } from '../../util/time.js';
|
||||
import { MProfile } from '../../mongo/profile.js';
|
||||
import { MBlacklist } from '../../mongo/blacklist.js';
|
||||
|
||||
|
||||
|
||||
export class ProfilesRoute {
|
||||
static load() {
|
||||
const app = Router();
|
||||
|
||||
|
||||
app.get('/:id', async (req, res) => {
|
||||
if (!req.params.id) return res.redirect('/');
|
||||
const player = await MProfile.findOne({ steam: req.params.id });
|
||||
if (!player) return res.render('profiles/private.ejs');
|
||||
const blacklist = await MBlacklist.findOne({ steam: req.params.id! });
|
||||
if (blacklist && blacklist.status) return res.render('profiles/private.ejs');
|
||||
const steam = await PlayerUtil.getPlayer(player?.steam!);
|
||||
const steamStats = await PlayerUtil.getPlayerStats(player?.steam!);
|
||||
|
||||
res.render('profiles/index.ejs', {
|
||||
player, steam, steamStats: steamStats,
|
||||
msToTime
|
||||
});
|
||||
})
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import dayjs from 'dayjs';
|
||||
import { PlayerUtil } from '../../util/PlayerUtil.js';
|
||||
import { msToTime } from '../../util/time.js';
|
||||
import { PipelineStage } from 'mongoose';
|
||||
import { MBlacklist } from '../../mongo/blacklist.js';
|
||||
|
||||
const generateSearch = (regex: RegExp) => [
|
||||
{
|
||||
@ -55,6 +56,8 @@ export class StationsRoute {
|
||||
app.get('/details/:id', async (req, res) => {
|
||||
if (!req.params.id) return res.redirect('/stations/');
|
||||
const record = await MLog.findOne({ id: req.params.id });
|
||||
const blacklist = await MBlacklist.findOne({ steam: record?.userSteamId! });
|
||||
if (blacklist && blacklist.status) return res.redirect('/stations/');
|
||||
const player = await PlayerUtil.getPlayer(record?.userSteamId!);
|
||||
|
||||
res.render('stations/details.ejs', {
|
||||
@ -65,44 +68,6 @@ export class StationsRoute {
|
||||
});
|
||||
})
|
||||
|
||||
app.get('/leaderboard/', async (req, res) => {
|
||||
const s = req.query.q?.toString().split(',').map(x => new RegExp(x, "i"));
|
||||
|
||||
const data = Object.keys(raw_schema)
|
||||
.reduce((o, key) => ({ ...o, [key]: `$${key}` }), {});
|
||||
|
||||
const filter: PipelineStage[] = [
|
||||
{
|
||||
$project: {
|
||||
// record.leftDate - record.joinedDate
|
||||
result: { $subtract: ['$leftDate', '$joinedDate'] },
|
||||
...data
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
s && filter.unshift(
|
||||
{
|
||||
$match: {
|
||||
$and: [
|
||||
...s.map(x => ({ $or: generateSearch(x) }))
|
||||
]
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
const records = await MLog.aggregate(filter)
|
||||
.sort({ result: -1 })
|
||||
.limit(30)
|
||||
res.render('stations/leaderboard.ejs', {
|
||||
records,
|
||||
dayjs,
|
||||
q: req.query.q,
|
||||
msToTime
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
// API ENDPOINTS
|
||||
// CREATE AN ISSUE IF YOU NEED API ACCESS: https://git.alekswilc.dev/alekswilc/simrail-logs/issues
|
||||
|
126
src/http/routes/trains.ts
Normal file
126
src/http/routes/trains.ts
Normal file
@ -0,0 +1,126 @@
|
||||
import { Router } from 'express';
|
||||
import dayjs from 'dayjs';
|
||||
import { PlayerUtil } from '../../util/PlayerUtil.js';
|
||||
import { msToTime } from '../../util/time.js';
|
||||
import { PipelineStage } from 'mongoose';
|
||||
import { MTrainLog, raw_schema } from '../../mongo/trainLogs.js';
|
||||
import { MBlacklist } from '../../mongo/blacklist.js';
|
||||
|
||||
const generateSearch = (regex: RegExp) => [
|
||||
{
|
||||
trainNumber: { $regex: regex },
|
||||
},
|
||||
{
|
||||
userSteamId: { $regex: regex },
|
||||
},
|
||||
{
|
||||
server: { $regex: regex },
|
||||
}
|
||||
]
|
||||
|
||||
export class TrainsRoute {
|
||||
static load() {
|
||||
const app = Router();
|
||||
|
||||
app.get('/', async (req, res) => {
|
||||
const s = req.query.q?.toString().split(',').map(x => new RegExp(x, "i"));
|
||||
|
||||
const filter: PipelineStage[] = [];
|
||||
|
||||
|
||||
s && filter.push({
|
||||
$match: {
|
||||
$and: [
|
||||
...s.map(x => ({ $or: generateSearch(x) }))
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
const records = await MTrainLog.aggregate(filter)
|
||||
.sort({ leftDate: -1 })
|
||||
.limit(30)
|
||||
res.render('trains/index.ejs', {
|
||||
records,
|
||||
dayjs,
|
||||
q: req.query.q,
|
||||
msToTime
|
||||
});
|
||||
})
|
||||
|
||||
app.get('/details/:id', async (req, res) => {
|
||||
if (!req.params.id) return res.redirect('/trains/');
|
||||
const record = await MTrainLog.findOne({ id: req.params.id });
|
||||
const player = await PlayerUtil.getPlayer(record?.userSteamId!);
|
||||
const blacklist = await MBlacklist.findOne({ steam: record?.userSteamId! });
|
||||
if (blacklist && blacklist.status) return res.redirect('/trains/');
|
||||
|
||||
res.render('trains/details.ejs', {
|
||||
record,
|
||||
dayjs,
|
||||
player,
|
||||
msToTime
|
||||
});
|
||||
})
|
||||
|
||||
app.get('/leaderboard/', async (req, res) => {
|
||||
const s = req.query.q?.toString().split(',').map(x => new RegExp(x, "i"));
|
||||
|
||||
const data = Object.keys(raw_schema)
|
||||
.reduce((o, key) => ({ ...o, [key]: `$${key}` }), {});
|
||||
|
||||
const filter: PipelineStage[] = [
|
||||
{
|
||||
$project: {
|
||||
// record.leftDate - record.joinedDate
|
||||
result: { $subtract: ['$leftDate', '$joinedDate'] },
|
||||
...data
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
s && filter.unshift(
|
||||
{
|
||||
$match: {
|
||||
$and: [
|
||||
...s.map(x => ({ $or: generateSearch(x) }))
|
||||
]
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
const records = await MTrainLog.aggregate(filter)
|
||||
.sort({ result: -1 })
|
||||
.limit(30)
|
||||
res.render('trains/leaderboard.ejs', {
|
||||
records,
|
||||
dayjs,
|
||||
q: req.query.q,
|
||||
msToTime
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
// API ENDPOINTS
|
||||
// CREATE AN ISSUE IF YOU NEED API ACCESS: https://git.alekswilc.dev/alekswilc/simrail-logs/issues
|
||||
/*
|
||||
app.get('/api/last', async (req, res) => {
|
||||
const records = await MLog.find()
|
||||
.sort({ leftDate: -1 })
|
||||
.limit(30)
|
||||
res.json({ code: 200, records });
|
||||
})
|
||||
|
||||
app.get('/api/search', async (req, res) => {
|
||||
if (!req.query.q) return res.send('invalid');
|
||||
const records = await MLog.find({ $text: { $search: req.query.q as string } })
|
||||
.sort({ leftDate: -1 })
|
||||
.limit(30)
|
||||
|
||||
res.json({ code: 200, records });
|
||||
})*/
|
||||
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
@ -2,6 +2,10 @@ import express from 'express';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import path from 'node:path';
|
||||
import { StationsRoute } from './routes/stations.js';
|
||||
import { TrainsRoute } from './routes/trains.js';
|
||||
import { ProfilesRoute } from './routes/profile.js';
|
||||
import { LeaderboardRoute } from './routes/leaderboard.js';
|
||||
import { MProfile } from '../mongo/profile.js';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@ -20,6 +24,28 @@ export class ApiModule {
|
||||
app.get('/details/:id', (req, res) => res.redirect('/stations/details/'+req.params.id));
|
||||
|
||||
app.use('/stations/', StationsRoute.load());
|
||||
app.use('/trains/', TrainsRoute.load());
|
||||
app.use('/profiles/', ProfilesRoute.load());
|
||||
app.use('/leaderboard/', LeaderboardRoute.load())
|
||||
|
||||
|
||||
app.get('/migrate', async () => {
|
||||
const _ = await MProfile.find({});
|
||||
|
||||
_.forEach(async(x) => {
|
||||
x.trainPoints = Object.values(x.trainStats).length === 1 ?
|
||||
Object.values(x.trainStats)[0].score :
|
||||
Object.values(x.trainStats).reduce((acc, curr) => acc + curr.score, 0)
|
||||
|
||||
x.trainDistance = Object.values(x.trainStats).length === 1 ?
|
||||
Object.values(x.trainStats)[0].distance :
|
||||
Object.values(x.trainStats).reduce((acc, curr) => acc + curr.distance, 0)
|
||||
|
||||
await MProfile.updateOne({ id: x.id }, { trainPoints: x.trainPoints, trainDistance: x.trainDistance })
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
|
||||
app.listen(2005);
|
||||
}
|
||||
|
@ -1,19 +1,11 @@
|
||||
<header>
|
||||
<h1><a style="color: white; text-decoration: none;" href="/">SimRail Logs</a></h1>
|
||||
|
||||
<% if (section==='stations' ) { %>
|
||||
<nav style="margin-bottom: 0;">
|
||||
<a href="/">Strona Główna</a> /
|
||||
<a href="https://git.alekswilc.dev/alekswilc/simrail-logs/issues/8">Logi pociągów</a>
|
||||
</nav>
|
||||
<nav>
|
||||
<a href="/stations/">Logi posterunków</a> /
|
||||
<a href="/stations/leaderboard">Tablica godzin</a>
|
||||
</nav>
|
||||
<% } else {%>
|
||||
<a href="/stations/">Logi posterunków</a> /
|
||||
<a href="https://git.alekswilc.dev/alekswilc/simrail-logs/issues/8">Logi pociągów</a>
|
||||
<% } %>
|
||||
<a href="/trains/">Logi pociągów</a> /
|
||||
<a href="/leaderboard/train">Tablica pociągow</a> /
|
||||
<a href="/leaderboard/station">Tablica posterunków</a>
|
||||
|
||||
<br />
|
||||
<p style="color: darkorange; font-size: 14px;">Hej! Podoba Ci się projekt? Polajkuj post na <a
|
||||
href="https://forum.simrail.eu/topic/9142-logowanie-wyj%C5%9B%C4%87-z-posterunk%C3%B3w/">forum</a>, a będzie
|
||||
|
@ -39,7 +39,7 @@
|
||||
<p>Planowane funkcjonalności</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>Obsługa pociągów (<a href="https://git.alekswilc.dev/alekswilc/simrail-logs/issues/8">#8</a>)</p>
|
||||
<p>Nowy wygląd aplikacji</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
77
src/http/views/leaderboard/index.ejs
Normal file
77
src/http/views/leaderboard/index.ejs
Normal file
@ -0,0 +1,77 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>simrail.alekswilc.dev</title>
|
||||
<meta name="description" content="Simrail Utils">
|
||||
<meta property="og:title" content="simrail.alekswilc.dev">
|
||||
<meta property="og:url" content="https://simrail.alekswilc.dev/leaderboard/">
|
||||
<meta property="og:description" content="Simrail Utils">
|
||||
<meta property="og:type" content="website">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/open-fonts@1.1.1/fonts/inter.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@exampledev/new.css@1.1.2/new.min.css">
|
||||
|
||||
<style>
|
||||
p {
|
||||
margin: 1%;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<%- include('../_modules/header.ejs', { section: 'leaderboard' }) %>
|
||||
|
||||
<h2 id="but">Tablica wyników</h2>
|
||||
<div class="container">
|
||||
<input type="text" id="search" value="<%-q%>">
|
||||
|
||||
<button onclick="search()">Szukaj</button>
|
||||
<button onclick="clearSearch()">Wyczyść</button>
|
||||
|
||||
<p>Użyj przecinka, aby wyszukać wiele wartości: pl2,Łazy</p>
|
||||
|
||||
</div>
|
||||
<br />
|
||||
<ul>
|
||||
<% records.forEach(record=> { %>
|
||||
<li>
|
||||
<%- type === 'train' ? include('train.ejs', { record, msToTime }) : include('station.ejs', { record, msToTime }) %>
|
||||
</li>
|
||||
<% }) %>
|
||||
</ul>
|
||||
|
||||
<% if (!records.length) { %>
|
||||
<h4>Nie znaleziono wyników dla twojego zapytania.</h4>
|
||||
<% } %>
|
||||
|
||||
|
||||
<script>
|
||||
function select() {
|
||||
const isTrain = "<%- type %>" === 'train'
|
||||
location.href = '/leaderboard/' + (isTrain ? 'station' : 'train')
|
||||
}
|
||||
document.getElementById('but').textContent = ("<%- type %>" === 'train') ? 'Tablica pociągów' : 'Tablica posterunków'
|
||||
function search() {
|
||||
location.href = '/leaderboard/<%- type %>/?q=' + document.getElementById('search').value
|
||||
}
|
||||
function clearSearch() {
|
||||
location.href = '/leaderboard/<%- type %>';
|
||||
}
|
||||
document.getElementById('search').addEventListener("keyup", (event) => {
|
||||
if (event.key === "Enter")
|
||||
search();
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
<hr>
|
||||
|
||||
<p style="color: orange;">Dane do rankingu zbierane są od dnia 19.08.2024.</p>
|
||||
|
||||
<%- include('../_modules/footer.ejs', { thanks: false }) %>
|
||||
</body>
|
||||
|
||||
</html>
|
9
src/http/views/leaderboard/station.ejs
Normal file
9
src/http/views/leaderboard/station.ejs
Normal file
@ -0,0 +1,9 @@
|
||||
<details>
|
||||
<summary><span style="color:hotpink">
|
||||
<%- record.steamName %>
|
||||
</span> <span style="color: lightskyblue">
|
||||
<%- msToTime(record.dispatcherTime) %>
|
||||
</span> </summary>
|
||||
<p>Spędzona liczba godzin: <%- msToTime(record.dispatcherTime) || 'Brak' %></p>
|
||||
<button onclick="location.href = '/profiles/<%- record.steam %>'">Więcej</button>
|
||||
</details>
|
11
src/http/views/leaderboard/train.ejs
Normal file
11
src/http/views/leaderboard/train.ejs
Normal file
@ -0,0 +1,11 @@
|
||||
<details>
|
||||
<summary><span style="color:hotpink">
|
||||
<%- record.steamName %>
|
||||
</span> - <span style="color:lightskyblue">
|
||||
<%- record.trainPoints %> pkt.
|
||||
</span></summary>
|
||||
<p>Spędzona liczba godzin: <%- msToTime(record.trainTime) %></p>
|
||||
<p>Przejechane kilometry: <%- record.trainDistance / 1000 %>km</p>
|
||||
<p>Zdobyte punkty: <%- record.trainPoints %></p>
|
||||
<button onclick="location.href = '/profiles/<%- record.steam %>'">Więcej</button>
|
||||
</details>
|
117
src/http/views/profiles/index.ejs
Normal file
117
src/http/views/profiles/index.ejs
Normal file
@ -0,0 +1,117 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>simrail.alekswilc.dev</title>
|
||||
<meta name="description"
|
||||
content="<%- steam.personaname %>">
|
||||
<meta property="og:title" content="Simrail Log">
|
||||
<meta property="og:url" content="https://simrail.alekswilc.dev/profiles/<%- player.steam %>/">
|
||||
<meta property="og:description"
|
||||
content="<%- steam.personaname %>">
|
||||
<meta property=" og:type" content="website">
|
||||
<meta property="og:image" content="<%- steam.avatarfull %>" />
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/open-fonts@1.1.1/fonts/inter.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@exampledev/new.css@1.1.2/new.min.css">
|
||||
|
||||
<style>
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<script>
|
||||
function copylink() {
|
||||
navigator.clipboard.writeText("https://simrail.alekswilc.dev/players/details/<%- player.steam %>/")
|
||||
}
|
||||
</script>
|
||||
|
||||
<body>
|
||||
<%- include('../_modules/header.ejs', { section: 'profiles' }) %>
|
||||
|
||||
<div class="details">
|
||||
<h1><a href="<%- steam.profileurl %>"><%- steam.personaname %></a></h1>
|
||||
|
||||
|
||||
<%if (steamStats.stats) {%>
|
||||
<details open>
|
||||
<summary>Statystyki Steam</summary>
|
||||
<p>Zdobyte punkty: <%- steamStats.stats.find(x => x.name === 'SCORE')?.value ?? "0" %></p>
|
||||
<p>Przejechane kilometry: <%- (steamStats.stats.find(x => x.name === 'DISTANCE_M')?.value / 1000) ?? "0" %></p>
|
||||
<p>Czas spędzony jako dyżurny ruchu: <%- msToTime((steamStats.stats.find(x => x.name === 'DISPATCHER_TIME')?.value ?? 0)*1_000_000) || 'Nigdy nie wszedł w tryb dyżurnego ruchu.' %></p>
|
||||
<br />
|
||||
<p style="font-size: smaller;">UWAGA: powyższe statystyki udostępnia platforma STEAM, mogą one być z łatwością manipulowane.</p>
|
||||
|
||||
</details>
|
||||
<%}%>
|
||||
|
||||
|
||||
<h1>Statystyki pociągów</h1>
|
||||
<% if (player.trainTime) {%>
|
||||
<p>Spędzony czas: <%- msToTime(player.trainTime) %></p>
|
||||
<p>Przejechane kilometry: <%- player.trainDistance / 1000 %>km</p>
|
||||
<p>Zdobyte punkty: <%- player.trainPoints %></p>
|
||||
<p>Średnia prędkość: <%- ((player.trainDistance / (player.trainTime / 1000)) * 3.6).toFixed(2) %> km/h</p>
|
||||
<%}%>
|
||||
<% if (player.trainStats && Object.keys(player.trainStats).length) {%>
|
||||
<ul>
|
||||
<% Object.keys(player.trainStats).forEach(name => {%>
|
||||
<li>
|
||||
<details open>
|
||||
<summary><%- name %></summary>
|
||||
<p>Przejechany dystans: <%- player.trainStats[name].distance / 1000 %>km</p>
|
||||
<p>Spędzony czas: <%- msToTime(player.trainStats[name].time) %></p>
|
||||
<p>Zdobyte punkty: <%- player.trainStats[name].score %></p>
|
||||
<p>Średnia prędkość: <%- ((player.trainStats[name].distance / (player.trainStats[name].time / 1000)) * 3.6).toFixed(2) %> km/h</p>
|
||||
</details>
|
||||
</li>
|
||||
|
||||
<% }) %>
|
||||
</ul>
|
||||
<%} else {%>
|
||||
<p>Brak danych</p>
|
||||
<%}%>
|
||||
|
||||
<h1>Statystyki posterunków</h1>
|
||||
<% if (player.dispatcherTime) {%>
|
||||
<p>Spędzony czas: <%- msToTime(player.dispatcherTime) %></p>
|
||||
<%}%>
|
||||
<% if (player.dispatcherStats && Object.keys(player.dispatcherStats).length) {%>
|
||||
<ul>
|
||||
<% Object.keys(player.dispatcherStats).forEach(name => {%>
|
||||
<li>
|
||||
<details open>
|
||||
<summary><%- name %></summary>
|
||||
<p>Spędzony czas: <%- msToTime(player.dispatcherStats[name].time) %></p>
|
||||
</details>
|
||||
</li>
|
||||
|
||||
<% }) %>
|
||||
</ul>
|
||||
<%} else {%>
|
||||
<p>Brak danych</p>
|
||||
<%}%>
|
||||
|
||||
<br />
|
||||
<p><button onclick="copylink()">Kopiuj link</button></p>
|
||||
</div>
|
||||
<hr>
|
||||
<p style="color: orange;">Dane do rankingu zbierane są od dnia 19.08.2024.</p>
|
||||
<%- include('../_modules/footer.ejs', { thanks: false }) %>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
47
src/http/views/profiles/private.ejs
Normal file
47
src/http/views/profiles/private.ejs
Normal file
@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>simrail.alekswilc.dev</title>
|
||||
<meta name="description"
|
||||
content="Profil prywatny">
|
||||
<meta property="og:title" content="Simrail Log">
|
||||
<meta property="og:url" content="https://simrail.alekswilc.dev/">
|
||||
<meta property="og:description"
|
||||
content="Profil prywatny">
|
||||
<meta property=" og:type" content="website">
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/open-fonts@1.1.1/fonts/inter.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@exampledev/new.css@1.1.2/new.min.css">
|
||||
|
||||
<style>
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<%- include('../_modules/header.ejs', { section: 'profiles' }) %>
|
||||
|
||||
<div class="details">
|
||||
<p>Profil gracza jest prywatny.</p>
|
||||
|
||||
</div>
|
||||
<hr>
|
||||
<%- include('../_modules/footer.ejs', { thanks: false }) %>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -6,13 +6,13 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>simrail.alekswilc.dev</title>
|
||||
<meta name="description"
|
||||
content="<%= record.stationName %> | <%= record.userUsername %> | <%= dayjs(record.leftDate).format('hh:mm DD/MM/YYYY') %>">
|
||||
content="<%- record.stationName %> | <%- record.userUsername %> | <%- dayjs(record.leftDate).format('hh:mm DD/MM/YYYY') %>">
|
||||
<meta property="og:title" content="Simrail Log">
|
||||
<meta property="og:url" content="https://simrail.alekswilc.dev/details/<%= record.id %>/">
|
||||
<meta property="og:url" content="https://simrail.alekswilc.dev/details/<%- record.id %>/">
|
||||
<meta property="og:description"
|
||||
content="<%= record.stationName %> | <%= record.userUsername %> | <%= dayjs(record.leftDate).format('hh:mm DD/MM/YYYY') %>"">
|
||||
content="<%- record.stationName %> | <%- record.userUsername %> | <%- dayjs(record.leftDate).format('hh:mm DD/MM/YYYY') %>"">
|
||||
<meta property=" og:type" content="website">
|
||||
<meta property="og:image" content="<%= record.userAvatar %>" />
|
||||
<meta property="og:image" content="<%- record.userAvatar %>" />
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/open-fonts@1.1.1/fonts/inter.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@exampledev/new.css@1.1.2/new.min.css">
|
||||
@ -40,7 +40,7 @@
|
||||
}
|
||||
|
||||
function copylink() {
|
||||
navigator.clipboard.writeText("https://simrail.alekswilc.dev/stations/details/<%= record.id %>/")
|
||||
navigator.clipboard.writeText("https://simrail.alekswilc.dev/stations/details/<%- record.id %>/")
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -49,28 +49,28 @@
|
||||
|
||||
<div class="details">
|
||||
|
||||
<p>Użytkownik: <a href="<%= player.profileurl %>">
|
||||
<%= record.userUsername %>
|
||||
<p>Użytkownik: <a href="/profiles/<%- record.userSteamId %>">
|
||||
<%- record.userUsername %>
|
||||
</a></p>
|
||||
<p>Stacja: <%= record.stationName %>
|
||||
<p>Stacja: <%- record.stationName %>
|
||||
</p>
|
||||
<p>Serwer: <%= record.server.toUpperCase() %>
|
||||
<p>Serwer: <%- record.server.toUpperCase() %>
|
||||
</p>
|
||||
<p>Data wejścia: <%= record.joinedDate ? dayjs(record.joinedDate).format('HH:mm DD/MM/YYYY') : '--:-- --/--/--'
|
||||
%> (<%= record.joinedDate ? dayjs(record.joinedDate).fromNow() : '--' %>)</p>
|
||||
<p>Data wyjścia: <%= dayjs(record.leftDate).format('HH:mm DD/MM/YYYY') %> (<%= dayjs(record.leftDate).fromNow()
|
||||
<p>Data wejścia: <%- record.joinedDate ? dayjs(record.joinedDate).format('HH:mm DD/MM/YYYY') : '--:-- --/--/--'
|
||||
%> (<%- record.joinedDate ? dayjs(record.joinedDate).fromNow() : '--' %>)</p>
|
||||
<p>Data wyjścia: <%- dayjs(record.leftDate).format('HH:mm DD/MM/YYYY') %> (<%- dayjs(record.leftDate).fromNow()
|
||||
%>)</p>
|
||||
<p>Spędzony czas: <%= record.joinedDate ? msToTime(record.leftDate - record.joinedDate) : '--' %>
|
||||
<p>Spędzony czas: <%- record.joinedDate ? msToTime(record.leftDate - record.joinedDate) : '--' %>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
<code class="clickable" style="white-space: pre-line" onclick="copydata()" id="data">;station: <%= record.stationName %>
|
||||
;steam: <%= record.userSteamId %>
|
||||
;server: <%= record.server %>
|
||||
;name: <%= record.userUsername %>
|
||||
;joined: <%=record.joinedDate ? dayjs(record.joinedDate).format() : 'no-data'%>
|
||||
;left: <%=dayjs(record.leftDate).format()%>
|
||||
;url: https://simrail.alekswilc.dev/stations/details/<%= record.id %>/
|
||||
<code class="clickable" style="white-space: pre-line" onclick="copydata()" id="data">;station: <%- record.stationName %>
|
||||
;steam: <%- record.userSteamId %>
|
||||
;server: <%- record.server %>
|
||||
;name: <%- record.userUsername %>
|
||||
;joined: <%-record.joinedDate ? dayjs(record.joinedDate).format() : 'no-data'%>
|
||||
;left: <%-dayjs(record.leftDate).format()%>
|
||||
;url: https://simrail.alekswilc.dev/stations/details/<%- record.id %>/
|
||||
</code>
|
||||
<br />
|
||||
<p><button onclick="copylink()">Kopiuj link</button></p>
|
||||
|
@ -26,7 +26,7 @@
|
||||
<h2>Wyszukaj posterunek, osobe lub serwer</h2>
|
||||
|
||||
<div class="container">
|
||||
<input type="text" id="search" value="<%=q%>">
|
||||
<input type="text" id="search" value="<%-q%>">
|
||||
<button onclick="search()">Szukaj</button>
|
||||
<button onclick="clearSearch()">Wyczyść</button>
|
||||
|
||||
@ -38,25 +38,25 @@
|
||||
<li>
|
||||
<details>
|
||||
<summary>[<span style="color:lightskyblue">
|
||||
<%= record.server.toUpperCase() %>
|
||||
<%- record.server.toUpperCase() %>
|
||||
</span>] <span style="color: lightskyblue">
|
||||
<%= record.stationName %>
|
||||
<%- record.stationName %>
|
||||
</span> - <span style="color:hotpink">
|
||||
<%= record.userUsername %>
|
||||
<%- record.userUsername %>
|
||||
</span>
|
||||
<p style="margin-bottom: 0; opacity: 0.5;">
|
||||
<%= dayjs(record.leftDate).format('HH:mm DD/MM/YYYY') %>
|
||||
<%- dayjs(record.leftDate).format('HH:mm DD/MM/YYYY') %>
|
||||
</p>
|
||||
</summary>
|
||||
<p>Data dołączenia: <%= record.joinedDate ? dayjs(record.joinedDate).format('HH:mm DD/MM/YYYY')
|
||||
: '--:-- --/--/--' %> (<%= record.joinedDate ? dayjs(record.joinedDate).fromNow() : '--' %>)
|
||||
<p>Data dołączenia: <%- record.joinedDate ? dayjs(record.joinedDate).format('HH:mm DD/MM/YYYY')
|
||||
: '--:-- --/--/--' %> (<%- record.joinedDate ? dayjs(record.joinedDate).fromNow() : '--' %>)
|
||||
</p>
|
||||
<p>Data wyjścia: <%= dayjs(record.leftDate).format('HH:mm DD/MM/YYYY') %> (<%=
|
||||
<p>Data wyjścia: <%- dayjs(record.leftDate).format('HH:mm DD/MM/YYYY') %> (<%-
|
||||
dayjs(record.leftDate).fromNow() %>)</p>
|
||||
<p>Spędzony czas: <%= record.joinedDate ? msToTime(record.leftDate - record.joinedDate) : '--' %>
|
||||
<p>Spędzony czas: <%- record.joinedDate ? msToTime(record.leftDate - record.joinedDate) : '--' %>
|
||||
</p>
|
||||
|
||||
<a href="/stations/details/<%= record.id %>">
|
||||
<a href="/stations/details/<%- record.id %>">
|
||||
<button>Więcej</button>
|
||||
</a>
|
||||
</details>
|
||||
|
94
src/http/views/trains/details.ejs
Normal file
94
src/http/views/trains/details.ejs
Normal file
@ -0,0 +1,94 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>simrail.alekswilc.dev</title>
|
||||
<meta name="description"
|
||||
content="<%- record.stationName %> | <%- record.userUsername %> | <%- dayjs(record.leftDate).format('hh:mm DD/MM/YYYY') %>">
|
||||
<meta property="og:title" content="Simrail Log">
|
||||
<meta property="og:url" content="https://simrail.alekswilc.dev/details/<%- record.id %>/">
|
||||
<meta property="og:description"
|
||||
content="<%- record.stationName %> | <%- record.userUsername %> | <%- dayjs(record.leftDate).format('hh:mm DD/MM/YYYY') %>"">
|
||||
<meta property=" og:type" content="website">
|
||||
<meta property="og:image" content="<%- record.userAvatar %>" />
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/open-fonts@1.1.1/fonts/inter.min.css">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@exampledev/new.css@1.1.2/new.min.css">
|
||||
|
||||
<style>
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<script>
|
||||
function copydata() {
|
||||
navigator.clipboard.writeText(document.getElementById('data').textContent.replace(/ /g, '').split('\n').filter(x => x).join(''))
|
||||
|
||||
}
|
||||
|
||||
function copylink() {
|
||||
navigator.clipboard.writeText("https://simrail.alekswilc.dev/trains/details/<%- record.id %>/")
|
||||
}
|
||||
</script>
|
||||
|
||||
<body>
|
||||
<%- include('../_modules/header.ejs', { section: 'trains' }) %>
|
||||
|
||||
<div class="details">
|
||||
|
||||
<p>Użytkownik: <a href="/profiles/<%- record.userSteamId %>">
|
||||
<%- record.userUsername %>
|
||||
</a></p>
|
||||
<p>Stacja: <%- record.stationName %>
|
||||
</p>
|
||||
<p>Pociąg: <%- record.trainName %> <%- record.trainNumber %>
|
||||
</p>
|
||||
<p>Data wejścia: <%- record.joinedDate ? dayjs(record.joinedDate).format('HH:mm DD/MM/YYYY') : '--:-- --/--/--'
|
||||
%> (<%- record.joinedDate ? dayjs(record.joinedDate).fromNow() : '--' %>)</p>
|
||||
<p>Data wyjścia: <%- dayjs(record.leftDate).format('HH:mm DD/MM/YYYY') %> (<%- dayjs(record.leftDate).fromNow()
|
||||
%>)</p>
|
||||
<p>Spędzony czas: <%- record.joinedDate ? msToTime(record.leftDate - record.joinedDate) : '--' %>
|
||||
</p>
|
||||
<% if (record.distance) { %>
|
||||
<p>Przejechane kilometry: <%- record.distance / 1000 %></p>
|
||||
<p>Zdobyte punkty: <%- record.points %></p>
|
||||
<p>Średnia prędkość: <%- ((record.distance / ((record.leftDate - record.joinedDate) / 1000)) * 3.6).toFixed(2) %> km/h</p>
|
||||
<% } %>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
<code class="clickable" style="white-space: pre-line" onclick="copydata()" id="data">;train: <%- record.trainNumber %>
|
||||
;steam: <%- record.userSteamId %>
|
||||
;server: <%- record.server %>
|
||||
;name: <%- record.userUsername %>
|
||||
;joined: <%-record.joinedDate ? dayjs(record.joinedDate).format() : 'no-data'%>
|
||||
;left: <%-dayjs(record.leftDate).format()%><%if (record.distance) {%>
|
||||
;distance: <%- record.distance / 1000 %>
|
||||
;points: <%- record.points %><%}%>
|
||||
;url: https://simrail.alekswilc.dev/trains/details/<%- record.id %>/
|
||||
</code>
|
||||
<br />
|
||||
<p><button onclick="copylink()">Kopiuj link</button></p>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<hr>
|
||||
<%- include('../_modules/footer.ejs', { thanks: false }) %>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -7,7 +7,7 @@
|
||||
<title>simrail.alekswilc.dev</title>
|
||||
<meta name="description" content="Simrail Utils">
|
||||
<meta property="og:title" content="simrail.alekswilc.dev">
|
||||
<meta property="og:url" content="https://simrail.alekswilc.dev/search?q=<%=q%>">
|
||||
<meta property="og:url" content="https://simrail.alekswilc.dev">
|
||||
<meta property="og:description" content="Simrail Utils">
|
||||
<meta property="og:type" content="website">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/open-fonts@1.1.1/fonts/inter.min.css">
|
||||
@ -18,46 +18,51 @@
|
||||
margin: 1%;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<%- include('../_modules/header.ejs', { section: 'stations' }) %>
|
||||
<%- include('../_modules/header.ejs', { section: 'trains' }) %>
|
||||
|
||||
<h2>Wyszukaj pociąg, osobe lub serwer</h2>
|
||||
|
||||
<h2>Tablica godzin</h2>
|
||||
<div class="container">
|
||||
<input type="text" id="search" value="<%=q%>">
|
||||
<button onclick="search()">Filtruj</button>
|
||||
<input type="text" id="search" value="<%-q%>">
|
||||
<button onclick="search()">Szukaj</button>
|
||||
<button onclick="clearSearch()">Wyczyść</button>
|
||||
|
||||
<p>Użyj przecinka, aby wyszukać wiele wartości: pl2,Łazy</p>
|
||||
<p>Użyj przecinka, aby wyszukać wiele wartości: pl2,1413</p>
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
<% records.forEach(record=> { %>
|
||||
<li>
|
||||
<details>
|
||||
<summary>[<span style="color:lightskyblue">
|
||||
<%= record.server.toUpperCase() %>
|
||||
<%- record.server.toUpperCase() %>
|
||||
</span>] <span style="color: lightskyblue">
|
||||
<%= record.stationName %>
|
||||
<%- record.trainName %>
|
||||
</span> - <span style="color: lightskyblue">
|
||||
<%- record.trainNumber %>
|
||||
</span> - <span style="color:hotpink">
|
||||
<%= record.userUsername %>
|
||||
</span>- <span style="color:lightseagreen">
|
||||
<%= record.joinedDate ? msToTime(record.leftDate - record.joinedDate) : '--' %>
|
||||
<%- record.userUsername %>
|
||||
</span>
|
||||
<p style="margin-bottom: 0; opacity: 0.5;">
|
||||
<%= dayjs(record.leftDate).format('HH:mm DD/MM/YYYY') %>
|
||||
<%- dayjs(record.leftDate).format('HH:mm DD/MM/YYYY') %>
|
||||
</p>
|
||||
</summary>
|
||||
<p>Data dołączenia: <%= record.joinedDate ? dayjs(record.joinedDate).format('HH:mm DD/MM/YYYY')
|
||||
: '--:-- --/--/--' %> (<%= record.joinedDate ? dayjs(record.joinedDate).fromNow() : '--' %>)
|
||||
<p>Data dołączenia: <%- record.joinedDate ? dayjs(record.joinedDate).format('HH:mm DD/MM/YYYY')
|
||||
: '--:-- --/--/--' %> (<%- record.joinedDate ? dayjs(record.joinedDate).fromNow() : '--' %>)
|
||||
</p>
|
||||
<p>Data wyjścia: <%= dayjs(record.leftDate).format('HH:mm DD/MM/YYYY') %> (<%=
|
||||
<p>Data wyjścia: <%- dayjs(record.leftDate).format('HH:mm DD/MM/YYYY') %> (<%-
|
||||
dayjs(record.leftDate).fromNow() %>)</p>
|
||||
<p>Spędzony czas: <%= record.joinedDate ? msToTime(record.leftDate - record.joinedDate) : '--' %>
|
||||
<p>Spędzony czas: <%- record.joinedDate ? msToTime(record.leftDate - record.joinedDate) : '--' %>
|
||||
<% if (record.distance) { %>
|
||||
<p>Przejechane kilometry: <%- record.distance / 1000 %></p>
|
||||
<p>Zdobyte punkty: <%- record.points %></p>
|
||||
<% } %>
|
||||
</p>
|
||||
|
||||
<a href="/details/<%= record.id %>">
|
||||
<a href="/trains/details/<%- record.id %>">
|
||||
<button>Więcej</button>
|
||||
</a>
|
||||
</details>
|
||||
@ -69,24 +74,24 @@
|
||||
<h4>Nie znaleziono wyników dla twojego zapytania.</h4>
|
||||
<% } %>
|
||||
|
||||
<hr>
|
||||
<%- include('../_modules/footer.ejs', { thanks: false }) %>
|
||||
|
||||
<script>
|
||||
function search() {
|
||||
location.href = '/stations/leaderboard?q=' + document.getElementById('search').value
|
||||
location.href = '/trains/?q=' + document.getElementById('search').value
|
||||
}
|
||||
|
||||
function clearSearch() {
|
||||
location.href = '/stations/leaderboard'
|
||||
console.log('test')
|
||||
location.href = '/trains/';
|
||||
}
|
||||
|
||||
document.getElementById('search').addEventListener("keyup", (event) => {
|
||||
if (event.key === "Enter")
|
||||
search();
|
||||
|
||||
});
|
||||
</script>
|
||||
<hr>
|
||||
<%- include('../_modules/footer.ejs', { thanks: false }) %>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
22
src/index.ts
22
src/index.ts
@ -6,7 +6,8 @@ import { StationsModule } from './modules/stations.js';
|
||||
import { ApiModule } from './http/server.js';
|
||||
import mongoose from 'mongoose';
|
||||
import { IPlayer } from './types/player.js';
|
||||
import { Station, Server } from '@simrail/types';
|
||||
import { Station, Server, Train } from '@simrail/types';
|
||||
import { TrainsModule } from './modules/trains.js';
|
||||
|
||||
|
||||
; (async () => {
|
||||
@ -23,15 +24,32 @@ import { Station, Server } from '@simrail/types';
|
||||
global.client = new SimrailClient();
|
||||
|
||||
client.on(SimrailClientEvents.StationJoined, (server: Server, station: Station, player: IPlayer) => {
|
||||
console.log(`${server.ServerCode} |${station.Name} | ${player.personaname} joined`);
|
||||
console.log(`${server.ServerCode} | ${station.Name} | ${player.personaname} joined`);
|
||||
});
|
||||
|
||||
client.on(SimrailClientEvents.StationLeft, (server: Server, station: Station, player: IPlayer, joinedAt: number) => {
|
||||
console.log(`${server.ServerCode} | ${station.Name} | ${player.personaname} left. | ${joinedAt ? dayjs(joinedAt).fromNow() : 'no time data.'}`);
|
||||
});
|
||||
|
||||
client.on(SimrailClientEvents.TrainLeft, (server: Server, train: Train, player: IPlayer, joinedAt: number, leftAt: number, points: number, distance: number, vehicle: string) => {
|
||||
console.log(`${server.ServerCode} | ${train.TrainName} | ${player.personaname} left. | ${joinedAt ? dayjs(joinedAt).fromNow() : 'no time data.'} |
|
||||
${vehicle} | ${distance / 1000} | ${points}`);
|
||||
});
|
||||
|
||||
client.on(SimrailClientEvents.TrainJoined, (server: Server, train: Train, player: IPlayer, start: number) => {
|
||||
console.log(`${server.ServerCode} | ${train.TrainName} | ${player.personaname} joined | ${start}`);
|
||||
});
|
||||
|
||||
|
||||
StationsModule.load();
|
||||
TrainsModule.load();
|
||||
ApiModule.load();
|
||||
|
||||
|
||||
process.on('unhandledRejection', (reason, promise) => {
|
||||
console.error(reason);
|
||||
console.error(promise);
|
||||
})
|
||||
})();
|
||||
|
||||
|
||||
|
@ -3,12 +3,37 @@ import { MLog } from '../mongo/logs.js';
|
||||
import { IPlayer } from '../types/player.js';
|
||||
import { SimrailClientEvents } from '../util/SimrailClient.js';
|
||||
import { v4 } from 'uuid';
|
||||
import { MProfile } from '../mongo/profile.js';
|
||||
import { PlayerUtil } from '../util/PlayerUtil.js';
|
||||
|
||||
export class StationsModule {
|
||||
public static load() {
|
||||
|
||||
client.on(SimrailClientEvents.StationLeft, (server: Server, station: Station, player: IPlayer, joinedAt: number) => {
|
||||
client.on(SimrailClientEvents.StationLeft, async (server: Server, station: Station, player: IPlayer, joinedAt: number) => {
|
||||
const stats = await PlayerUtil.getPlayerStats(player.steamid);
|
||||
const date = new Date();
|
||||
if (stats) {
|
||||
const time = (date.getTime() - joinedAt) ?? 0;
|
||||
|
||||
const userProfile = await MProfile.findOne({ steam: player.steamid }) ?? await MProfile.create({ steam: player.steamid, id: v4(), steamName: player.personaname });
|
||||
if (!userProfile.dispatcherStats) userProfile.dispatcherStats = {};
|
||||
|
||||
if (userProfile.dispatcherStats[station.Name]) {
|
||||
userProfile.dispatcherStats[station.Name].time = userProfile.dispatcherStats[station.Name].time + time;
|
||||
|
||||
} else {
|
||||
userProfile.dispatcherStats[station.Name] = {
|
||||
time
|
||||
}
|
||||
}
|
||||
if (Number.isNaN(userProfile.dispatcherStats[station.Name].time)) userProfile.dispatcherStats[station.Name].time = 0;
|
||||
|
||||
if (!userProfile.dispatcherTime) userProfile.dispatcherTime = 0;
|
||||
|
||||
userProfile.dispatcherTime = userProfile.dispatcherTime + time;
|
||||
|
||||
await MProfile.findOneAndUpdate({ id: userProfile.id }, { dispatcherStats: userProfile.dispatcherStats, dispatcherTime: userProfile.dispatcherTime })
|
||||
}
|
||||
|
||||
MLog.create({
|
||||
id: v4(),
|
||||
|
61
src/modules/trains.ts
Normal file
61
src/modules/trains.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import { Server, Station, Train } from '@simrail/types';
|
||||
import { MLog } from '../mongo/logs.js';
|
||||
import { IPlayer } from '../types/player.js';
|
||||
import { SimrailClientEvents } from '../util/SimrailClient.js';
|
||||
import { v4 } from 'uuid';
|
||||
import { getVehicle } from '../util/contants.js';
|
||||
import { MProfile } from '../mongo/profile.js';
|
||||
import { MTrainLog } from '../mongo/trainLogs.js';
|
||||
|
||||
export class TrainsModule {
|
||||
public static load() {
|
||||
|
||||
client.on(SimrailClientEvents.TrainLeft, async (server: Server, train: Train, player: IPlayer, joinedAt: number, leftAt: number, points: number, distance: number, vehicle: string) => {
|
||||
if (distance) {
|
||||
const time = (leftAt - joinedAt) ?? 0;
|
||||
const userProfile = await MProfile.findOne({ steam: player.steamid }) ?? await MProfile.create({ steam: player.steamid, id: v4(), steamName: player.personaname });
|
||||
|
||||
const vehicleName = getVehicle(vehicle) ?? vehicle;
|
||||
|
||||
if (!userProfile.trainStats) userProfile.trainStats = {};
|
||||
|
||||
if (userProfile.trainStats[vehicleName]) {
|
||||
userProfile.trainStats[vehicleName].distance = userProfile.trainStats[vehicleName].distance + distance;
|
||||
userProfile.trainStats[vehicleName].score = userProfile.trainStats[vehicleName].score + points;
|
||||
userProfile.trainStats[vehicleName].time = userProfile.trainStats[vehicleName].time + time;
|
||||
} else {
|
||||
userProfile.trainStats[vehicleName] = {
|
||||
distance, score: points, time
|
||||
}
|
||||
}
|
||||
|
||||
if (!userProfile.trainTime) userProfile.trainTime = 0;
|
||||
|
||||
userProfile.trainTime = userProfile.trainTime + time;
|
||||
|
||||
if (!userProfile.trainPoints) userProfile.trainPoints = 0;
|
||||
|
||||
userProfile.trainPoints = userProfile.trainPoints + points;
|
||||
|
||||
if (!userProfile.trainDistance) userProfile.trainDistance = 0;
|
||||
|
||||
userProfile.trainDistance = userProfile.trainDistance + distance;
|
||||
|
||||
await MProfile.findOneAndUpdate({ id: userProfile.id }, { trainStats: userProfile.trainStats, trainTime: userProfile.trainTime, trainPoints: userProfile.trainPoints, trainDistance: userProfile.trainDistance });
|
||||
}
|
||||
|
||||
MTrainLog.create({
|
||||
id: v4(),
|
||||
userSteamId: player.steamid,
|
||||
userAvatar: player.avatarfull,
|
||||
userUsername: player.personaname,
|
||||
joinedDate: joinedAt,
|
||||
leftDate: leftAt,
|
||||
trainNumber: train.TrainNoLocal,
|
||||
server: server.ServerCode,
|
||||
distance, points,
|
||||
trainName: train.TrainName
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
24
src/mongo/blacklist.ts
Normal file
24
src/mongo/blacklist.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { Model, model, Schema } from 'mongoose';
|
||||
|
||||
|
||||
export const raw_schema = {
|
||||
steam: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
status: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
}
|
||||
|
||||
const schema = new Schema<IBlacklist>(raw_schema);
|
||||
|
||||
export type TMBlacklist = Model<IBlacklist>
|
||||
|
||||
export const MBlacklist = model<IBlacklist>('blacklist', schema);
|
||||
|
||||
export interface IBlacklist {
|
||||
steam: string
|
||||
status: boolean
|
||||
}
|
78
src/mongo/profile.ts
Normal file
78
src/mongo/profile.ts
Normal file
@ -0,0 +1,78 @@
|
||||
import { Model, model, Schema } from 'mongoose';
|
||||
|
||||
|
||||
export const raw_schema = {
|
||||
id: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
steam: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
steamName: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
|
||||
trainStats: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: {}
|
||||
},
|
||||
dispatcherStats: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: {}
|
||||
},
|
||||
trainTime: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 0
|
||||
},
|
||||
trainPoints: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 0
|
||||
},
|
||||
trainDistance: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 0
|
||||
},
|
||||
dispatcherTime: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 0
|
||||
},
|
||||
}
|
||||
|
||||
const schema = new Schema<IProfile>(raw_schema);
|
||||
|
||||
|
||||
export type TMProfile = Model<IProfile>
|
||||
|
||||
export const MProfile = model<IProfile>('profile', schema);
|
||||
|
||||
export interface IProfile {
|
||||
id: string
|
||||
steam: string
|
||||
trainStats: {
|
||||
[trainName: string]: {
|
||||
score: number,
|
||||
distance: number
|
||||
time: number,
|
||||
}
|
||||
}
|
||||
dispatcherStats: {
|
||||
[name: string]: {
|
||||
time: number
|
||||
}
|
||||
}
|
||||
|
||||
dispatcherTime: number;
|
||||
trainTime: number
|
||||
trainPoints: number
|
||||
steamName: string
|
||||
trainDistance: number
|
||||
}
|
72
src/mongo/trainLogs.ts
Normal file
72
src/mongo/trainLogs.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import { Model, model, Schema } from 'mongoose';
|
||||
|
||||
|
||||
export const raw_schema = {
|
||||
id: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
trainNumber: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
userSteamId: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
userUsername: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
userAvatar: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
joinedDate: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: undefined
|
||||
},
|
||||
leftDate: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
distance: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 0
|
||||
},
|
||||
points: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 0
|
||||
},
|
||||
server: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
trainName: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
}
|
||||
|
||||
const schema = new Schema<ITrainLog>(raw_schema);
|
||||
|
||||
export type TMTrainLog = Model<ITrainLog>
|
||||
|
||||
export const MTrainLog = model<ITrainLog>('train_logs', schema);
|
||||
|
||||
export interface ITrainLog {
|
||||
id: string
|
||||
userSteamId: string
|
||||
userUsername: string
|
||||
userAvatar: string
|
||||
joinedDate?: number
|
||||
leftDate: number
|
||||
trainNumber: string
|
||||
trainName: string
|
||||
distance: number
|
||||
points: number
|
||||
server: string
|
||||
}
|
@ -21,8 +21,48 @@ export type IPlayer = {
|
||||
locstatecode: string
|
||||
}
|
||||
|
||||
export type IPlayerStats = {
|
||||
"steamID": string,
|
||||
"gameName": string,
|
||||
"stats": [
|
||||
{
|
||||
"name": "SCORE",
|
||||
"value": number
|
||||
},
|
||||
{
|
||||
"name": "DISPATCHER_TIME",
|
||||
"value": number
|
||||
},
|
||||
{
|
||||
"name": "DISTANCE_M",
|
||||
"value": number
|
||||
}
|
||||
],
|
||||
"achievements": [
|
||||
{
|
||||
"name": "FINISH_MISSION",
|
||||
"achieved": 0 | 1
|
||||
},
|
||||
{
|
||||
"name": "FINISH_ON_TIME",
|
||||
"achieved": 0 | 1
|
||||
},
|
||||
{
|
||||
"name": "FINISH_NIGHT",
|
||||
"achieved": 0 | 1
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
export type IPlayerPayload = {
|
||||
response: {
|
||||
players: IPlayer[]
|
||||
}
|
||||
}
|
||||
|
||||
export type IPlayerStatsPayload = {
|
||||
playerstats: IPlayerStats
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { IPlayerPayload } from '../types/player.js';
|
||||
import { IPlayerPayload, IPlayerStatsPayload } from '../types/player.js';
|
||||
|
||||
const STEAM_API_KEY = process.env.STEAM_APIKEY;
|
||||
|
||||
@ -8,4 +8,10 @@ export class PlayerUtil {
|
||||
if (!data.response.players) return;
|
||||
return data.response.players[0];
|
||||
}
|
||||
|
||||
public static async getPlayerStats(steamId: string) {
|
||||
const data = (await fetch(`http://api.steampowered.com/ISteamUserStats/GetUserStatsForGame/v0002/?appid=1422130&key=${STEAM_API_KEY}&steamid=${steamId}`).then(x => x.json())) as IPlayerStatsPayload;
|
||||
if (!data.playerstats?.stats) return;
|
||||
return data.playerstats;
|
||||
}
|
||||
}
|
@ -2,17 +2,24 @@ import { EventEmitter } from 'node:events';
|
||||
|
||||
import { IPlayer } from '../types/player.js';
|
||||
import { PlayerUtil } from './PlayerUtil.js';
|
||||
import { Station, ApiResponse, Server } from '@simrail/types';
|
||||
import { Station, ApiResponse, Server, Train } from '@simrail/types';
|
||||
|
||||
export enum SimrailClientEvents {
|
||||
StationJoined = 'stationJoined',
|
||||
StationLeft = 'stationLeft',
|
||||
TrainJoined = 'trainJoined',
|
||||
TrainLeft = 'trainLeft',
|
||||
|
||||
}
|
||||
|
||||
export declare interface SimrailClient {
|
||||
on(event: SimrailClientEvents.StationJoined, listener: (server: Server, station: Station, player: IPlayer) => void): this;
|
||||
on(event: SimrailClientEvents.StationLeft, listener: (server: Server, station: Station, player: IPlayer, joinedAt: number) => void): this;
|
||||
|
||||
|
||||
on(event: SimrailClientEvents.TrainJoined, listener: (server: Server, train: Train, player: IPlayer, startDistance: number) => void): this;
|
||||
on(event: SimrailClientEvents.TrainLeft, listener: (server: Server, train: Train, player: IPlayer, joinedAt: number, leftAt: number, points: number, distance: number, vehicle: string) => void): this;
|
||||
|
||||
//on(event: string, listener: Function): this;
|
||||
}
|
||||
|
||||
@ -21,10 +28,20 @@ export type OccupiedStation = {
|
||||
JoinedAt: number;
|
||||
}
|
||||
|
||||
export type OccupiedTrain = {
|
||||
SteamId: string;
|
||||
JoinedAt: number;
|
||||
StartPlayerDistance: number;
|
||||
StartPlayerPoints: number;
|
||||
}
|
||||
|
||||
export class SimrailClient extends EventEmitter {
|
||||
public stations: Record<Server['ServerCode'], Station[]> = {};
|
||||
public stationsOccupied: Record<Server['ServerCode'], Record<string, OccupiedStation | null>> = {};
|
||||
|
||||
public trains: Record<Server['ServerCode'], Train[]> = {};
|
||||
public trainsOccupied: Record<Server['ServerCode'], Record<string, OccupiedTrain | null>> = {};
|
||||
|
||||
public constructor() {
|
||||
super();
|
||||
this.setup();
|
||||
@ -37,16 +54,28 @@ export class SimrailClient extends EventEmitter {
|
||||
return { player, joinedAt: this.stationsOccupied[name].joinedAt };
|
||||
}
|
||||
|
||||
public getTrain(server: Server['ServerCode'], name: string) {
|
||||
if (!this.trainsOccupied[server] || !this.trainsOccupied[server][name]) return null;
|
||||
const player = PlayerUtil.getPlayer(this.trainsOccupied[server][name].SteamId);
|
||||
return { player, joinedAt: this.trainsOccupied[server][name].JoinedAt, startPlayerDistance: this.trainsOccupied[server][name].StartPlayerDistance };
|
||||
}
|
||||
|
||||
|
||||
private async setup() {
|
||||
if (!await redis.json.get('stations'))
|
||||
redis.json.set('stations', '$', []);
|
||||
if (!await redis.json.get('trains'))
|
||||
redis.json.set('trains', '$', []);
|
||||
if (!await redis.json.get('trains_occupied'))
|
||||
redis.json.set('trains_occupied', '$', {});
|
||||
|
||||
if (!await redis.json.get('stations_occupied'))
|
||||
redis.json.set('stations_occupied', '$', {});
|
||||
|
||||
this.stations = (await redis.json.get('stations') as unknown as SimrailClient['stations']);
|
||||
this.stationsOccupied = (await redis.json.get('stations_occupied') as unknown as SimrailClient['stationsOccupied']);
|
||||
this.trains = (await redis.json.get('trains') as unknown as SimrailClient['trains']);
|
||||
this.trainsOccupied = (await redis.json.get('trains_occupied') as unknown as SimrailClient['trainsOccupied']);
|
||||
}
|
||||
|
||||
|
||||
@ -59,48 +88,113 @@ export class SimrailClient extends EventEmitter {
|
||||
// TODO: check performance
|
||||
servers.forEach(async (server) => {
|
||||
const stations = (await fetch('https://panel.simrail.eu:8084/stations-open?serverCode=' + server.ServerCode).then(x => x.json())) as ApiResponse<Station>;
|
||||
if (!stations.result) return;
|
||||
const trains = (await fetch('https://panel.simrail.eu:8084/trains-open?serverCode=' + server.ServerCode).then(x => x.json())) as ApiResponse<Train>;
|
||||
if (stations.result) {
|
||||
if (!this.stations[server.ServerCode]) this.stations[server.ServerCode] = [];
|
||||
if (!this.stationsOccupied[server.ServerCode]) this.stationsOccupied[server.ServerCode] = {};
|
||||
|
||||
if (!this.stations[server.ServerCode]) this.stations[server.ServerCode] = [];
|
||||
if (!this.stationsOccupied[server.ServerCode]) this.stationsOccupied[server.ServerCode] = {};
|
||||
if (!this.stations[server.ServerCode].length) {
|
||||
this.stations[server.ServerCode] = stations.data;
|
||||
redis.json.set('stations', '$', this.stations);
|
||||
return;
|
||||
}
|
||||
|
||||
stations.data.forEach(async (x) => {
|
||||
const data = this.stations[server.ServerCode].find(y => y.Name === x.Name);
|
||||
if (!data) return;
|
||||
|
||||
if (data.DispatchedBy[0]?.SteamId !== x.DispatchedBy[0]?.SteamId) {
|
||||
if (!data.DispatchedBy[0]?.SteamId) {
|
||||
// join
|
||||
const date = new Date();
|
||||
const player = await PlayerUtil.getPlayer(x.DispatchedBy[0]?.SteamId);
|
||||
|
||||
this.emit(SimrailClientEvents.StationJoined, server, x, player);
|
||||
this.stationsOccupied[server.ServerCode][data.Prefix] = {
|
||||
SteamId: x.DispatchedBy[0]?.SteamId,
|
||||
JoinedAt: date.getTime()
|
||||
};
|
||||
|
||||
return;
|
||||
}
|
||||
// leave
|
||||
const player = await PlayerUtil.getPlayer(data.DispatchedBy[0]?.SteamId)
|
||||
|
||||
this.emit(SimrailClientEvents.StationLeft, server, x, player, this.stationsOccupied[server.ServerCode][data.Prefix]?.JoinedAt);
|
||||
delete this.stationsOccupied[server.ServerCode][data.Prefix];
|
||||
|
||||
}
|
||||
})
|
||||
redis.json.set('stations_occupied', '$', this.stationsOccupied);
|
||||
|
||||
if (!this.stations[server.ServerCode].length) {
|
||||
this.stations[server.ServerCode] = stations.data;
|
||||
redis.json.set('stations', '$', this.stations);
|
||||
return;
|
||||
}
|
||||
|
||||
stations.data.forEach(async (x) => {
|
||||
const data = this.stations[server.ServerCode].find(y => y.Name === x.Name);
|
||||
if (!data) return;
|
||||
if (trains.result) {
|
||||
if (!this.trains[server.ServerCode]) this.trains[server.ServerCode] = [];
|
||||
if (!this.trainsOccupied[server.ServerCode]) this.trainsOccupied[server.ServerCode] = {};
|
||||
|
||||
if (data.DispatchedBy[0]?.SteamId !== x.DispatchedBy[0]?.SteamId) {
|
||||
if (!data.DispatchedBy[0]?.SteamId) {
|
||||
// join
|
||||
const date = new Date();
|
||||
const player = await PlayerUtil.getPlayer(x.DispatchedBy[0]?.SteamId);
|
||||
|
||||
this.emit(SimrailClientEvents.StationJoined, server, x, player);
|
||||
this.stationsOccupied[server.ServerCode][data.Prefix] = {
|
||||
SteamId: x.DispatchedBy[0]?.SteamId,
|
||||
JoinedAt: date.getTime()
|
||||
};
|
||||
redis.json.set('stations_occupied', '$', this.stationsOccupied);
|
||||
|
||||
return;
|
||||
}
|
||||
// leave
|
||||
const player = await PlayerUtil.getPlayer(data.DispatchedBy[0]?.SteamId)
|
||||
|
||||
this.emit(SimrailClientEvents.StationLeft, server, x, player, this.stationsOccupied[server.ServerCode][data.Prefix]?.JoinedAt);
|
||||
delete this.stationsOccupied[server.ServerCode][data.Prefix];
|
||||
redis.json.set('stations_occupied', '$', this.stationsOccupied);
|
||||
if (!this.trains[server.ServerCode].length) {
|
||||
this.trains[server.ServerCode] = trains.data;
|
||||
redis.json.set('trains', '$', this.trains);
|
||||
return;
|
||||
}
|
||||
})
|
||||
|
||||
trains.data.forEach(async (x) => {
|
||||
const data = this.trains[server.ServerCode].find(y => y.id === x.id);
|
||||
if (!data) return;
|
||||
|
||||
if (data.TrainData.ControlledBySteamID !== x.TrainData.ControlledBySteamID) {
|
||||
if (!data.TrainData.ControlledBySteamID) {
|
||||
if (!x.TrainData.ControlledBySteamID) return;
|
||||
// join
|
||||
const date = new Date();
|
||||
const player = await PlayerUtil.getPlayer(x.TrainData.ControlledBySteamID!);
|
||||
const playerStats = await PlayerUtil.getPlayerStats(x.TrainData.ControlledBySteamID!);
|
||||
|
||||
this.emit(SimrailClientEvents.TrainJoined, server, x, player, playerStats?.stats.find(x => x.name === 'DISTANCE_M')?.value);
|
||||
|
||||
this.trainsOccupied[server.ServerCode][x.TrainNoLocal] = {
|
||||
SteamId: x.TrainData.ControlledBySteamID!,
|
||||
JoinedAt: date.getTime(),
|
||||
StartPlayerDistance: playerStats?.stats.find(x => x.name === 'DISTANCE_M')?.value!,
|
||||
StartPlayerPoints: playerStats?.stats.find(x => x.name === "SCORE")?.value!,
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data.TrainData.ControlledBySteamID) return;
|
||||
const date = new Date();
|
||||
|
||||
const player = await PlayerUtil.getPlayer(data.TrainData.ControlledBySteamID!);
|
||||
const playerId = data.TrainData.ControlledBySteamID!;
|
||||
const trainOccupied = this.trainsOccupied[server.ServerCode][data.TrainNoLocal];
|
||||
|
||||
setTimeout(async () => {
|
||||
const playerStats = await PlayerUtil.getPlayerStats(playerId);
|
||||
const oldKm = trainOccupied?.StartPlayerDistance ?? 0;
|
||||
|
||||
const distance = oldKm ? (playerStats?.stats.find(x => x.name === 'DISTANCE_M')?.value ?? 0) - oldKm : 0;
|
||||
|
||||
const oldPoints = trainOccupied?.StartPlayerPoints ?? 0;
|
||||
const points = oldPoints ? (playerStats?.stats.find(x => x.name === 'SCORE')?.value ?? 0) - oldPoints : 0;
|
||||
|
||||
|
||||
this.emit(SimrailClientEvents.TrainLeft, server, data, player, trainOccupied?.JoinedAt, date.getTime(), points, distance, x.Vehicles[0]);
|
||||
}, 60000)
|
||||
delete this.trainsOccupied[server.ServerCode][data.TrainNoLocal];
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
this.trains[server.ServerCode] = trains.data;
|
||||
redis.json.set('trains', '$', this.trains);
|
||||
redis.json.set('trains_occupied', '$', this.trainsOccupied);
|
||||
}
|
||||
|
||||
|
||||
this.stations[server.ServerCode] = stations.data;
|
||||
redis.json.set('stations', '$', this.stations);
|
||||
});
|
||||
}
|
||||
}
|
127
src/util/contants.ts
Normal file
127
src/util/contants.ts
Normal file
@ -0,0 +1,127 @@
|
||||
import wcmatch from 'wildcard-match'
|
||||
|
||||
/*
|
||||
E186_134 = "Traxx/E186-134",
|
||||
E186_929 = "Traxx/E186-929",
|
||||
E6ACTa_014 = "Dragon2/E6ACTa-014",
|
||||
E6ACTa_016 = "Dragon2/E6ACTa-016",
|
||||
E6ACTadb_027 = "Dragon2/E6ACTadb-027",
|
||||
ED250_018 = "Pendolino/ED250-018 Variant",
|
||||
EN57_009 = "EN57/EN57-009",
|
||||
EN57_047 = "EN57/EN57-047",
|
||||
EN57_1000 = "EN57/EN57-1000",
|
||||
EN57_1003 = "EN57/EN57-1003",
|
||||
EN57_1051 = "EN57/EN57-1051",
|
||||
EN57_1219 = "EN57/EN57-1219",
|
||||
EN57_1316 = "EN57/EN57-1316",
|
||||
EN57_1458 = "EN57/EN57-1458",
|
||||
EN57_1567 = "EN57/EN57-1567",
|
||||
EN57_1571 = "EN57/EN57-1571",
|
||||
EN57_1752 = "EN57/EN57-1752",
|
||||
EN57_1755 = "EN57/EN57-1755",
|
||||
EN57_1796 = "EN57/EN57-1796",
|
||||
EN57_1821 = "EN57/EN57-1821",
|
||||
EN57_614 = "EN57/EN57-614",
|
||||
EN71_005 = "EN57/EN71-005",
|
||||
EN71_011 = "EN57/EN71-011",
|
||||
EN76_006 = "Elf/EN76-006",
|
||||
EN76_022 = "Elf/EN76-022",
|
||||
EN96_001 = "Elf/EN96-001",
|
||||
EP07_135 = "4E/EP07-135",
|
||||
EP07_174 = "4E/EP07-174",
|
||||
EP08_001 = "4E/EP08-001",
|
||||
EP08_013 = "4E/EP08-013",
|
||||
ET22_1163 = "201E/ET22-1163", -- DLC required: 2868050
|
||||
ET22_243 = "201E/ET22-243", -- DLC required: 2868050
|
||||
ET22_256 = "201E/ET22-256", -- DLC required: 2868050
|
||||
ET22_644 = "201E/ET22-644", -- DLC required: 2868050
|
||||
ET22_836 = "201E/ET22-836", -- DLC required: 2868050
|
||||
ET22_911 = "201E/ET22-911", -- DLC required: 2868050
|
||||
ET25_002 = "Dragon2/ET25-002",
|
||||
EU07_005 = "4E/EU07-005",
|
||||
EU07_068 = "4E/EU07-068",
|
||||
EU07_085 = "4E/EU07-085",
|
||||
EU07_092 = "4E/EU07-092",
|
||||
EU07_096 = "4E/EU07-096",
|
||||
EU07_241 = "4E/EU07-241",
|
||||
*/
|
||||
|
||||
export const trainsList = [
|
||||
{
|
||||
train: 'Traxx (E186)',
|
||||
pattern: [
|
||||
'Traxx/E186-*',
|
||||
]
|
||||
},
|
||||
{
|
||||
train: 'Dragon2 (E6ACTa, E6ACTadb)',
|
||||
pattern: [
|
||||
'Dragon2/E6ACTa-*',
|
||||
'Dragon2/E6ACTadb-*'
|
||||
]
|
||||
},
|
||||
{
|
||||
train: 'Dragon2 (ET25)',
|
||||
pattern: [
|
||||
'Dragon2/ET25-*',
|
||||
]
|
||||
},
|
||||
{
|
||||
train: 'Pendolino (ED250)',
|
||||
pattern: [
|
||||
'Pendolino/ED250-*',
|
||||
]
|
||||
},
|
||||
{
|
||||
train: 'EN57',
|
||||
pattern: [
|
||||
'EN57/EN57-*',
|
||||
]
|
||||
},
|
||||
{
|
||||
train: 'EN71',
|
||||
pattern: [
|
||||
'EN57/EN71-*',
|
||||
]
|
||||
},
|
||||
{
|
||||
train: 'EN96',
|
||||
pattern: [
|
||||
'Elf/EN76-*',
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
train: 'EP07',
|
||||
pattern: [
|
||||
'4E/EP07-*',
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
train: 'EP08',
|
||||
pattern: [
|
||||
'4E/EP08-*',
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
train: 'ET22',
|
||||
pattern: [
|
||||
'201E/ET22-*',
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
train: 'EU07',
|
||||
pattern: [
|
||||
'4E/EU07-*',
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
export const getVehicle = (name: string) => {
|
||||
return trainsList.find(x => wcmatch(x.pattern)(name))?.train;
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user