Giter VIP home page Giter VIP logo

mc-chat-parser's Introduction

Minecraft Chat Parser

A Discord chat-bot that connects a specified Discord channel with a Minecraft server in-game chat, allowing to pass messages between the two.

Features

  • Messages from a Discord channel appear in Minecraft in-game chat as:

    <username> message content
    
    • The username of the Discord user sending the message (not the bot) is used.
    • Color is added to the <username> to help distinguish it from other in-game chat (defaults to teal).
    • The message content supports some emojis, but not all of them.
  • Messages from Minecraft in-game chat appear in a Discord text channel as:

    📷 username [BOT] MM/DD/YYYY HH:MM AM/PM
    message content
    
    • Player username is used as the sender
    • The display image 📷 is replaced with the head of the player avatar using the https://minotar.net/ API together with the player username, for example:

    head for username

    • Username and timestamp format defaults to what Discord uses, the [BOT] label is added by Discord automatically.
    • The message content is sent as-is (e.g. :D will appear as text, not as 😄)
  • Discord bot will indicate player presence on the server with custom status messages:

    • It will set its status to 🌙Idle and a custom status message to Waiting for players when there are no players on the server.
    • It will set its status to 🟢Online when there are players and set the status message to Watching username if only one player is on the server, and Watching # players when the number of players is #. In the latter case, the full list of online usernames is visible in the bot activity details.

Installation

Discord bot setup

  1. Create a new bot application in the Discord Developer Portal.
  2. In Settings > Bot use the Reset Token button to generate a new token, copy that for later.
  3. In Settings > Bot > Privileged Gateway Intents enable PRESENCE INTENT and MESSAGE CONTENT INTENT options.
  4. In Settings > OAuth2 > Url Generator enable the scope bot and bot permissions Manage Webhooks, Read Messages/View Channels, Send Messages, and Use Embedded Activities.
  5. Visit the generated URL to invite the bot into your Discord channel.
  6. Copy the ID of a Discord text channel you want the bot to participate
    • enable Developer Mode (under User Settings > Advanced)
    • right-click on the channel to get the ID.

Chat application setup

The bot requires RCON access to a Minecraft server instance to be able to send in-game messages and to get the list of online players, and read access to the Minecraft log file to read the in-game chat messages.

An example compose file is included with the project to show how to run the bot together with a Minecraft server instance that is leveraging the https://github.com/itzg/docker-minecraft-server docker image. Fill in the empty env variables and run docker compose up -d.

Alternatively, the bot can also be executed as a stand-alone Node.js application running on the same server where your Minecraft instance is located. Requires Node 18 or later to be present on the server.

  • clone this repo,
  • run npm install,
  • run npm run build,
  • create a .env file from .env.example and fill in the config variables in that file,
  • and run node dist/app.js

Configuration

  • DISCORD_TOKEN - Discord access token generated during bot setup.
  • DISCORD_CHANNEL_ID - Text channel ID where the bot participates.
  • DISCORD_LOGIN_TIMEOUT - Number of milliseconds the bot waits to establish the initial Discord session. Defaults to 60000.
  • WEBHOOK_NAME - Pretty much an arbitrary name for the webhook. Defaults to mc-chat-parser.
  • RCON_PASSWORD - Password for the Minecraft server instance RCON connection.
  • RCON_HOST - Hostname or IP for the RCON connection. Defaults to localhost.
  • RCON_PORT - Port number for the RCON connection. Defaults to 25575.
  • SENDER_COLOR - Color to display the <username> part in the in-game chat. Defaults to #2CBAA8 (teal).
  • LOG_FILE - Path to the Minecraft server logs file. Defaults to /logs/latest.log
  • TIMESTAMP_PATTERN - Timestamp format used in Minecraft server logs file. Defaults to \d{2}:\d{2}:\d{2}

Authors

Licence

ISC

Contribution

  1. Start by creating an issue https://github.com/KartulUdus/mc-chat-parser/issue.
  2. Fork and modify.
  3. Add/update tests (sufficiently, a subjective measure).
  4. Make sure tests pass (npm run test).
  5. Make sure ESLint passes (npm run lint).
  6. Update the version nr in package.json following Semantic Versioning 2.0.0.
  7. Reference the issue nr in the branch (e.g. feature/nr-few-words) and commit messages.
  8. Create a pull request.

mc-chat-parser's People

Contributors

jaakkytt avatar derek-maekask avatar kartuludus avatar

Watchers

 avatar  avatar

mc-chat-parser's Issues

Exit with an error if the log file is not readable

Currently, the app logs a warning and continues to run:

Cannot start. Does the file exist? [Error: ENOENT: no such file or directory, open '/logs/latest.log'] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: '/logs/latest.log'
}

I suggest to:

  • Use an on-failure:10 restart policy for the container
  • Add an ordered start-up check such that the least invasive checks are done first (log file > rcon > discord)

Add support for message retry if delivery fails

Message sending might fail due to connection (discord) or resource (rcon) issues. Since current error handling forces the app to restart, it might lose additional interactions that occur during a boot-up.

Improve error handling to identify which errors are temporary and recoverable by a retry and which should be considered fatal for the application.

Uncaught Exception: Error: Login timed out
    at Timeout._onTimeout (file:///usr/src/app/dist/service/discordClient.js:62:37)
    at listOnTimeout (node:internal/timers:569:17)
    at process.processTimers (node:internal/timers:512:7)
/usr/src/app/node_modules/rcon-client/lib/rcon.js:117
                    reject(new Error(`Timeout for packet id ${id}`));

Uncaught Exception: Error: Timeout for packet id 17
    at Timeout._onTimeout (/usr/src/app/node_modules/rcon-client/lib/rcon.js:117:28)
    at listOnTimeout (node:internal/timers:569:17)
    at process.processTimers (node:internal/timers:512:7)

Separate conjoined log entries

It seems that TailFile.on(data) indeed would capture multiple messages in one event if they are sent close enough in time.

The most simple example can be seen on startup:

log entry: 2023-10-16 09:39:26 [RCON Listener #2/INFO]: Thread RCON Client /172.25.0.3 started
2023-10-16 09:39:26 [Server thread/INFO]: [Not Secure] [Rcon] Chat-bot joined
  • Match individual log entries by ^timestam [ and process them separately.

(not a real regex example)

Clean up logging

Since the bot also logs the entries it sees, it makes the bot output log a bit messy and difficult to distinguish which message is from the bot and which is from the game server.

Review log entries, and formats, and delimit the content reflected from the game server logs. Review assigned log levels.

Avoid leaving promises pending indefinitely

Hard to reproduce.

A couple of times the following error has reached the logs:

Possible AsyncEventEmitter memory leak detected. 11 ready listeners added to WebSocketShard.
Use emitter.setMaxListeners() to increase the limit.

Quick Google, possibly related to:
node-fetch/node-fetch#1295

So far it has not yet killed the bot, but it would be prudent to consume all promises instead of leaving them dangling.

MC log rotation seems to break log file following

After identifying that the bot was not picking up chat messages from the game...

File on disk:
-rw-rw-r-- 1 player player 6764 Oct 14 20:55 latest.log

File in the mc-chat-parser container
-rw-rw-r-- 1 1001 1001 20177 Oct 13 20:53 latest.log

As a temporary solution the container could be scheduled to restart when the log file changes (lazy option triggered by date). Since https://github.com/logdna/tail-file-node#how-log-rolling-is-handled should handle rolling logs, perhaps it's the docker file mapping that is breaking it. Test if adjusting the volume map to the folder instead of a direct file would fix the issue.

Separate direct dependency between components at startup

Restructure the app.js file into 2 clearly defined blocks: startup checks and listener registrations - such that none of the components (discord client, discord webhook, rcon, log reader) would require each other during the startup checks.

Restart the app, if the startup fails (til restart: on-failure:10 will finally end its life).

Move discord webhook existence check and creation into the startup, away from send (to make sure the bot has the permissions to use a webhook in the first place).

Perform startup check of components in the order of log reader, rcon, discord client, and discord webhook to fail as fast as possible.

Add pipelines

It's annoying to publish a new docker image every time something is merged to master.

Automate it, every time something is merged to master, publish a new package to dockerhub with a new version number

feature req: add threads

User should be able to use a thread instead of a channel to parse messages.

If a thread is not specified, it should use the channel.

The thread needs both channel and thread ID as env vars

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.