1Description
This bot enables two-way communication between Discord and your MU Online Season 8 server. The administrator can send messages from phone or PC via Discord — without logging into the game!
The message appears in-game in two places simultaneously:
🟡 Yellow broadcast in the middle of the screen
💬 In the [POST] chat window
Requirements
MU Online server with CustomChat table in the database
Windows Server with Python 3.11+
SQL Server with Windows Authentication or login/password access
Discord account + own bot (Discord Developer Portal)
Step by step installation
1. Create table in SQL Server
CREATE TABLE [dbo].[CustomChat](
[chat_id] [int] IDENTITY(1,1) NOT NULL,
[type] [smallint] NOT NULL DEFAULT 0,
[name] [varchar](10) NOT NULL DEFAULT '',
[message] [varchar](200) NOT NULL,
[delivered] [tinyint] NOT NULL DEFAULT 0,
CONSTRAINT [PK_CustomChat] PRIMARY KEY CLUSTERED ([chat_id] ASC)
)2. Create Discord Bot
Go to discord.com/developers/applications
New Application → give it a name
Go to Bot tab → Reset Token → copy the token
Enable Message Content Intent
OAuth2 → URL Generator → scope: bot → permissions: Send Messages, Read Message History, Add Reactions
Copy the generated link and add the bot to your Discord server
3. Install Python on VPS
powershell -Command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; Invoke-WebRequest -Uri 'https://www.python.org/ftp/python/3.11.9/python-3.11.9-amd64.exe' -OutFile 'C:\python_installer.exe'"
C:\python_installer.exe /quiet InstallAllUsers=1 PrependPath=14. Install required libraries
"C:\Program Files\Python311\python.exe" -m pip install discord.py pyodbc
5. Create bot folder and files
Create folder C:\DiscordToGame\ with these files:
bot.py:
import discord
import pyodbc
import configparser
import logging
import re
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[
logging.FileHandler("discord_to_game.log", encoding="utf-8"),
logging.StreamHandler()
]
)
log = logging.getLogger(__name__)
config = configparser.ConfigParser()
config.read("config.ini", encoding="utf-8")
BOT_TOKEN = config["Bot"]["Token"]
CHANNEL_ID = int(config["Bot"]["ChannelId"])
ALLOWED_ROLES = [r.strip() for r in config["Bot"]["AllowedRoles"].split(",") if r.strip()]
SENDER_NAME = config["Bot"].get("SenderName", "Discord")[:10]
PREFIX = config["Bot"].get("Prefix", "")
DB_SERVER = config["Database"]["Server"]
DB_NAME = config["Database"]["Database"]
DB_USER = config["Database"].get("User", "")
DB_PASS = config["Database"].get("Password", "")
intents = discord.Intents.default()
intents.message_content = True
client = discord.Client(intents=intents)
def get_db():
if DB_USER:
conn_str = f"DRIVER={{SQL Server}};SERVER={DB_SERVER};DATABASE={DB_NAME};UID={DB_USER};PWD={DB_PASS};"
else:
conn_str = f"DRIVER={{SQL Server}};SERVER={DB_SERVER};DATABASE={DB_NAME};Trusted_Connection=yes;"
return pyodbc.connect(conn_str, autocommit=True)
def remove_emoji(text):
replacements = {
'🙂': '
', '😊': '
', '😀': '
', '😃': '
', '😄': '
',
'😆': '
', '😂': '
', '🤣': '
', '😉': '
', '😎': 'B)',
'😍': '<3', '🥰': '<3', '❤️': '<3', '❤': '<3',
'💪': ':muscle:', '👍': '+1', '👎': '-1',
'🔥': ':fire:', '😢': '
', '😭': "
", '😡': '
',
}
for emoji, text_eq in replacements.items():
text = text.replace(emoji, text_eq)
return re.sub(r'[^\x00-\x7FÀ-ɏa-zA-Z0-9 .,!?:;()\-_<>+\'/\\@#$%^&*=\[\]{}|~`]', '', text).strip()
def insert_message(name, message, raw_text):
sql = "INSERT INTO CustomChat (type, name, message, delivered) VALUES (?, ?, ?, 0)"
with get_db() as conn:
conn.execute(sql, (0, name[:10], message[:200])) # yellow notice
conn.execute(sql, (2, name[:10], raw_text[:200])) # POST chat
def user_has_permission(member):
if not ALLOWED_ROLES:
return True
return any(role.name in ALLOWED_ROLES for role in member.roles)
@client.event
async def on_ready():
log.info(f"Bot logged in as {client.user}")
ch = client.get_channel(CHANNEL_ID)
if ch:
log.info(f"Listening to channel: #{ch.name}")
else:
log.warning(f"Channel ID={CHANNEL_ID} not found. Check config.ini.")
@client.event
async def on_message(msg):
if msg.author.bot:
return
if msg.channel.id != CHANNEL_ID:
return
if not user_has_permission(msg.author):
await msg.add_reaction("❌")
return
text = remove_emoji(msg.content)
if PREFIX:
if not text.startswith(PREFIX):
return
text = text[len(PREFIX):].strip()
if not text:
return
try:
game_message = f"{SENDER_NAME}: {text}"
insert_message(SENDER_NAME, game_message, text)
await msg.add_reaction("✅")
log.info(f"[{msg.author}] -> Game: {game_message}")
except Exception as e:
await msg.add_reaction("❌")
log.error(f"Database error: {e}")
client.run(BOT_TOKEN)config.ini:
[Bot]
; Discord bot token from Developer Portal
Token = YOUR_DISCORD_BOT_TOKEN
; Discord channel ID where you will write messages to game
; (Enable Developer Mode in Discord settings → right click channel → Copy ID)
ChannelId = 0
; Discord roles allowed to send messages to game (comma separated)
; Leave empty = everyone can write
AllowedRoles = Admin,Moderator
; Sender name visible in game (max 10 characters)
SenderName = Discord
; Message prefix (optional). Example: "!" means you type: !Hello players
; Leave empty = every message in channel goes to game
Prefix =
[Database]
; SQL Server address
Server = (local)
; Database name
Database = MuOnline
; Leave empty = Windows Authentication
; Fill in = SQL Server Authentication
User =
Password =6. Run the bot
cd C:\DiscordToGame && "C:\Program Files\Python311\python.exe" bot.pyConfiguration options
Option Description
Token Bot token from Discord Developer Portal
ChannelId Discord channel ID (right click channel → Copy ID)
AllowedRoles Roles allowed to write to game
SenderName Name shown in game (max 10 characters)
Server SQL Server address (default (local))
Database Database name (default MuOnline)
User/Password SQL Server login (empty = Windows Auth)
Secure your Discord channel
Right click channel → Edit Channel → Permissions
@everyone → Send Messages → ❌
Add Admin role → Send Messages → ✅
How it works
You write on Discord
↓
Python Bot receives the message
↓
Bot inserts record into SQL Server (CustomChat table)
↓
GameServer reads the record and displays in game
↓
Players see the message in game! 🎮
Result in game
🟡 Yellow notice (middle of screen): Discord: Hello players!
💬 POST chat: [POST]Discord: Hello players!
✅ Discord reaction confirms message was delivered
Notes
Bot must be running on VPS at all times
Requires CustomChat table — if your server doesn't have it, use the SQL above
Tested on MU Online Season 8 with SQL Server 2012 on Windows Server 2016
The type values (0 = notice, 2 = POST chat) may differ depending on your GameServer version — test with different values if needed
Created for MU Online private server community 💪