A Robotic Process Automation (RPA) framework for Mahjong Soul (雀魂)
This project is a fork of Cryolite's majsoul-rpa, but has been completely redesigned based on the proactor pattern. While some API names and design ideas were borrowed, the architecture and codebase are entirely new.
Note
This framework is intended to enable the participation of bots in friendly matches and tournaments where bot participation is agreed upon by all players involved.
This framework does not support the functionality to enter bots into open matches (including, but not limited to, ranked matches and special rooms within tournament matches). Furthermore, there is no intention to introduce such functionality in the future.
Warning
Users of this framework accept full responsibility for its use. The authors shall bear no liability whatsoever for any damages resulting from utilization of this framework, including, but not limited to, account suspension or legal repercussions.
🚧 Work in Progress
MajsoulRPA is currently in active development. Login, Home screen operations, friendly-room management, tournament-lobby entry, and in-match gameplay are available.
Workarounds for some in-match situations are still being developed, using the v1-develop branch as a reference for established behavior and match-flow knowledge.
Tournament-room operations remain unimplemented, so tournament matches cannot yet be automated end to end.
- ✅ Requires Python 3.12 or later
- 🗑️ Removed dependencies on Docker, Redis, and mitmproxy
- 🖥️ Supports moving browser window position after launch
- 🖱️ Mouse can be used freely even while RPA is running
- 📐 Supports browser viewport sizes other than 1920 × 1080
- 🀄 Supports three-player mahjong
Because WebSocket capture no longer uses mitmproxy, installing a local CA certificate is no longer required.
majsoulrpa$ pip install .[browser]
# Install Chromium browser binaries on the browser host
majsoulrpa$ playwright install chromium --with-depsmajsoulrpa$ pip install .[rpa]majsoulrpa$ pip install .[browser,rpa]majsoulrpa$ pip install .[s3]Make AWS credentials available using one of the following methods:
-
Save them in
~/.aws/credentials -
Set them via environment variables:
export AWS_ACCESS_KEY_ID=... export AWS_SECRET_ACCESS_KEY=... export AWS_REGION=...
You can launch the remote browser directly from the command line:
majsoulrpa-browserIt can also be invoked from Python code:
import asyncio
from majsoulrpa import AppConfig
from majsoulrpa.browser import run_browser_host
asyncio.run(run_browser_host(AppConfig()))The RPA client is used from Python code. A typical flow looks like this:
import asyncio
from typing import Any
from majsoulrpa import AppConfig, RPAApp
from majsoulrpa.screens.home import HomeScreen
from majsoulrpa.screens.login import LoginScreen
rpa = RPAApp()
@rpa.on(LoginScreen)
async def on_login(screen: LoginScreen, data: Any) -> Any:
...
return data
@rpa.on(HomeScreen)
async def on_home(screen: HomeScreen, data: Any) -> Any:
...
return data
data = ... # You can set any value here; it will be carried through the client
asyncio.run(rpa.run(AppConfig(), data))- Register callbacks with
@rpa.on(Screen) - Only the registered Screens are subject to detection; unregistered ones are ignored
datacan hold arbitrary values and is passed along within the client- Call
rpa.run(...)to start execution
See examples/ for complete implementations.
Important
The email address you use must be linked to your Yostar ID.
Some rare in-match layouts cannot be implemented safely until their click
coordinates have been confirmed. MajsoulRPA stops without clicking a guessed
position and raises ScreenNotImplementedOperationError. The exception carries
the screenshot captured when the unsupported layout was encountered. You can
save it as follows:
from pathlib import Path
from majsoulrpa.screens import ScreenNotImplementedOperationError
try:
...
except ScreenNotImplementedOperationError as error:
error.save_screenshot(Path("screenshots"))
# Saved as screenshots/YYYYMMDDTHHMMSSZ-ScreenNotImplementedOperationError.png
raiseIf you encounter this exception, please help us investigate the layout by opening an issue with:
- the operation being attempted and the number and order of its candidates;
- the saved screenshot; and
- any relevant decoded Sniffer logs, after redacting account IDs and authentication information such as tokens.
Before sharing the screenshot, redact any account name or other personal information. Before sharing Sniffer logs, redact account IDs, tokens, cookies, and any other authentication information.
Licensed under the MIT license.
