Compare commits
12 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ed492e9045 | |||
| 24f65956ab | |||
| 4e6668c2e5 | |||
| 696e8f1749 | |||
| a28796751a | |||
| 58451f6fd0 | |||
| 87a3cb158c | |||
| 9337105ca7 | |||
| 1e35792419 | |||
| bcc98514e6 | |||
| 885461f316 | |||
| f4a872546a |
25
README.md
|
|
@ -1,31 +1,30 @@
|
|||
# Farming Simulator 25 - Discord Bot
|
||||
|
||||
This bot periodically updates a Discord channel with stats from a Farming Simulator 25 server.
|
||||
It posts the server name, password, time, and player count. Written in Node.js, it uses the
|
||||
discord.js library to interact with Discord and fetches server stats via the XML feed
|
||||
This bot periodically updates a Discord channel with stats from a Farming Simulator 25 server.
|
||||
It posts the server name, password, time, and player count. Written in Node.js, it uses the
|
||||
discord.js library to interact with Discord and fetches server stats via the XML feed
|
||||
(accessible through the server's web interface). The update interval is configurable.
|
||||
|
||||
|
||||
## Screenshots
|
||||
|
||||
<details>
|
||||
<summary>Discord embed in english</summary>
|
||||
|
||||

|
||||

|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Discord embed in german</summary>
|
||||
|
||||

|
||||

|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Terminal output (NodeJS)</summary>
|
||||
|
||||

|
||||

|
||||
|
||||
</details>
|
||||
|
||||
|
|
@ -57,8 +56,8 @@ discord.js library to interact with Discord and fetches server stats via the XML
|
|||
|
||||
1. Clone the repository to your server
|
||||
2. Locate the configuration files:
|
||||
- Use either
|
||||
- `config.example-de.json` (for German)
|
||||
- Use either
|
||||
- `config.example-de.json` (for German)
|
||||
- `config.example-en.json` (for English)
|
||||
- Rename the chosen file to `config.json`.
|
||||
3. Open `config.json` and fill in the required fields:
|
||||
|
|
@ -73,21 +72,27 @@ discord.js library to interact with Discord and fetches server stats via the XML
|
|||
|
||||
1. Navigate to the root directory of the cloned repository.
|
||||
2. Build and start the container:
|
||||
|
||||
```bash
|
||||
docker-compose up -d --build
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
3. The bot should now be running and posting server stats to the specified Discord channel.
|
||||
|
||||
### Option 2: Run Without Docker (Using Node.js)
|
||||
|
||||
1. Navigate to the root directory of the cloned repository.
|
||||
2. Install dependencies:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
3. Start the bot:
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
4. The bot should now be running and posting server stats to the specified Discord channel.
|
||||
- Note: Closing the terminal will stop the bot. Use a process manager like [PM2](https://pm2.io/) to keep it running.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"application": {
|
||||
"serverPassword": "TypeMyServerPasswordHere",
|
||||
"serverStatsUrl": "http://1.1.1.1:8080/feed/dedicated-server-stats.xml",
|
||||
"serverMapUrl": "http://1.1.1.1:8080/feed/dedicated-server-stats-map.jpg",
|
||||
"serverStatsUrl": "http://127.0.0.1:8080/feed/dedicated-server-stats.xml",
|
||||
"serverMapUrl": "http://127.0.0.1:8080/feed/dedicated-server-stats-map.jpg",
|
||||
"updateIntervalSeconds": 30
|
||||
},
|
||||
"discord": {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"application": {
|
||||
"serverPassword": "TypeMyServerPasswordHere",
|
||||
"serverStatsUrl": "http://1.1.1.1:8080/feed/dedicated-server-stats.xml",
|
||||
"serverMapUrl": "http://1.1.1.1:8080/feed/dedicated-server-stats-map.jpg",
|
||||
"serverStatsUrl": "http://127.0.0.1:8080/feed/dedicated-server-stats.xml",
|
||||
"serverMapUrl": "http://127.0.0.1:8080/feed/dedicated-server-stats-map.jpg",
|
||||
"updateIntervalSeconds": 30
|
||||
},
|
||||
"discord": {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
version: "2"
|
||||
|
||||
services:
|
||||
ls25bot:
|
||||
build:
|
||||
|
|
@ -24,4 +22,14 @@ services:
|
|||
sleep 7200 # Each 2 hours
|
||||
echo "Restarting ls25bot container at $(date)"
|
||||
docker restart ls25bot
|
||||
done
|
||||
done
|
||||
|
||||
# This is used for development purposes only
|
||||
webserver:
|
||||
image: nginx:alpine
|
||||
container_name: ls25bot-webserver
|
||||
restart: always
|
||||
volumes:
|
||||
- ./misc/files:/usr/share/nginx/html
|
||||
ports:
|
||||
- "8080:80"
|
||||
BIN
misc/files/feed/dedicated-server-stats-map.jpg
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
BIN
misc/images/socials/GitHub Repository Header.afphoto
Normal file
BIN
misc/images/socials/GitHub Repository Header.png
Normal file
|
After Width: | Height: | Size: 166 KiB |
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "ls25-discord-bot",
|
||||
"version": "0.1.6",
|
||||
"version": "0.1.8",
|
||||
"description": "A simple discord bot for farming simulator 25",
|
||||
"main": "source/Main.ts",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -92,6 +92,16 @@ export default class DiscordEmbed {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncates a string at a given length
|
||||
* @param text The input text to truncate
|
||||
* @param maxLength The allowed characters until truncation
|
||||
* @returns The truncated string
|
||||
*/
|
||||
private async truncateText(text: string, maxLength = 1024): Promise<string> {
|
||||
return text.length > maxLength ? text.slice(0, maxLength - 3) + '...' : text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send server stats embed in a channel
|
||||
* @param serverStats
|
||||
|
|
@ -100,8 +110,6 @@ export default class DiscordEmbed {
|
|||
let embed = new EmbedBuilder();
|
||||
let config = this.appConfiguration;
|
||||
|
||||
serverStats.getServerMonth();
|
||||
|
||||
embed.setTitle(config.translation.discordEmbed.title);
|
||||
if (!serverStats.isOnline()) {
|
||||
embed.setColor(0xCA0000);
|
||||
|
|
@ -115,6 +123,8 @@ export default class DiscordEmbed {
|
|||
embed.setThumbnail(config.application.serverMapUrl);
|
||||
|
||||
let playerListString: string;
|
||||
let playerListTitleString = `${config.translation.discordEmbed.titlePlayerCount} (${serverStats.getPlayerCount()??0}/${serverStats.getMaxPlayerCount()??0}):`;
|
||||
|
||||
if(serverStats.getPlayerList().length === 0) {
|
||||
playerListString = config.translation.discordEmbed.noPlayersOnline;
|
||||
} else {
|
||||
|
|
@ -129,7 +139,7 @@ export default class DiscordEmbed {
|
|||
let serverMods = serverStats.getServerMods();
|
||||
let serverModsText = "-/-";
|
||||
if(serverMods.length > 0) {
|
||||
serverModsText = serverMods.map(mod => `${mod.name}`).join(', ');
|
||||
serverModsText = await this.truncateText(serverMods.map(mod => `${mod.name}`).join(', '));
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
|
|
@ -140,12 +150,11 @@ export default class DiscordEmbed {
|
|||
{name: config.translation.discordEmbed.titleServerMap, value: serverStats.getServerMap()},
|
||||
{name: config.translation.discordEmbed.titleServerMods, value: serverModsText},
|
||||
{
|
||||
name: `${config.translation.discordEmbed.titlePlayerCount} (${serverStats.getPlayerCount()}/${serverStats.getMaxPlayerCount()}):`,
|
||||
name: playerListTitleString,
|
||||
value: playerListString
|
||||
},
|
||||
);
|
||||
}
|
||||
this.appLogger.debug(embed);
|
||||
return embed;
|
||||
}
|
||||
}
|
||||
|
|
@ -137,37 +137,6 @@ export default class ServerStatusFeed {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the server month as a string
|
||||
* @returns {string} The server month as a string
|
||||
*/
|
||||
public getServerMonth(): string {
|
||||
let config: IConfiguration = Configuration.getConfiguration();
|
||||
let dayTime = this.getServerStats()?.Server.dayTime;
|
||||
if (dayTime === undefined) {
|
||||
return "Error";
|
||||
}
|
||||
let month = dayTime / (60 * 60 * 1000 * 24);
|
||||
month = month % 1;
|
||||
month = month * 12;
|
||||
month = Math.floor(month);
|
||||
let months = [
|
||||
config.translation.common.monthJanuary,
|
||||
config.translation.common.monthFebruary,
|
||||
config.translation.common.monthMarch,
|
||||
config.translation.common.monthApril,
|
||||
config.translation.common.monthMay,
|
||||
config.translation.common.monthJune,
|
||||
config.translation.common.monthJuly,
|
||||
config.translation.common.monthAugust,
|
||||
config.translation.common.monthSeptember,
|
||||
config.translation.common.monthOctober,
|
||||
config.translation.common.monthNovember,
|
||||
config.translation.common.monthDecember
|
||||
]
|
||||
return months[month-1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the server time in the format HH:MM
|
||||
* @returns {string} The server time in the format HH:MM
|
||||
|
|
@ -187,23 +156,23 @@ export default class ServerStatusFeed {
|
|||
if(minutesString.length === 1) {
|
||||
minutesString = `0${minutesString}`;
|
||||
}
|
||||
return `${hoursString}:${minutesString} (${this.getServerMonth()})`;
|
||||
return `${hoursString}:${minutesString}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the server player count
|
||||
* @returns {number} The server player count
|
||||
* @returns {number | null | undefined} The server player count
|
||||
*/
|
||||
public getPlayerCount(): number {
|
||||
return <number>this.getServerStats()?.Server.Slots.numUsed;
|
||||
public getPlayerCount(): number | null | undefined {
|
||||
return <number>this.getServerStats()?.Server?.Slots?.numUsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the server player count
|
||||
* @returns {number} The server player count
|
||||
* @returns {number | null | undefined} The server player count
|
||||
*/
|
||||
public getMaxPlayerCount(): number {
|
||||
return <number>this.getServerStats()?.Server.Slots.capacity;
|
||||
public getMaxPlayerCount(): number | null | undefined {
|
||||
return <number>this.getServerStats()?.Server?.Slots?.capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||