Giter Club home page Giter Club logo

akagi's Introduction


Akagi

「死ねば助かるのに………」- 赤木しげる



Ask me anything about this at Discord

中文
Report Bug . Request Feature

About The Project

"The purpose of this project is to provide people with a convenient way to real-time understand their performance in Majsoul game matches and to learn and improve from it. This project is intended for educational purposes only, and the author is not responsible for any actions taken by users using this project. Majsoul officials may detect abnormal behavior, and any consequences such as account suspension are not related to the author."

image

Akagi.mp4

Usage

Flowchart

Flow

Setup

Installation.

YouTube Video for you to follow.

You will need:

  1. A mortal.pth. (Get one from Discord server if you don't have one.)
  2. (Optional, Recommend) Use Windows Terminal to open client.py for a nice looking TUI.
  3. (Optional) If you want to use Steam, Majsoul Plus, or anything other client, proxy the client using tools like proxifier.

Get mortal.pth at Discord

  1. Go to #verify and click the ✅ reaction.
  2. Go to #bot-zip
  3. Download a bot you like.
  4. Extract the zip.
  5. And mortal.pth is there.

Akagi:

Windows

Download install_akagi.ps1 at Release

  1. Put install_akagi.ps1 at the location you want to install Akagi.
  2. Open Powershell as Administrator
  3. cd in to the directory
  4. Run: Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
  5. Run: install_akagi.ps1
  6. Open mitmproxy if this is your first time using it.
  7. Close it.
  8. Go to your user home directory ~/.mitmproxy
  9. Install the certificate.
  10. Put mortal.pth into ./Akagi/mjai/bot

Mac

Download install_akagi.command from Release

  1. Place install_akagi.command in the location where you want to install Akagi.
  2. Download the latest Python installation package from the Python official website and install it (skip this step if you already have a compatible version of Python installed).
  3. Open Terminal and cd to the directory where install_akagi.command is located.
  4. Execute: bash install_akagi.command
  5. After installation is complete, enter the Akagi folder.
  6. Double-click run_agaki.command to start Akagi.
  7. If you are using mitmproxy for the first time, click on "start mitm".
  8. Close it.
  9. Go to your user home directory ~/.mitmproxy.
  10. Install the certificate.
  11. Put mortal.pth into ./Akagi/mjai/bot.

settings.json

  • Unlocker: Decide to use MajsoulUnlocker or not.
  • v10: If your Majsoul client in still in v0.10.x and you want to use MajsoulUnlocker, set it to true.
  • Autoplay: Autoplay.
  • Helper: To use mahjong-helper or not
  • Autohu: Auto Ron.
  • Port:
    • MITM: The MITM Port, you should redirect Majsoul connection to this port.
    • XMLRPC: The XMLRPC Port.
    • MJAI: The port bind to MJAI bot container.
  • Playwright:
    • enable: Enable the playwright
    • width: width of the viewport of playwright
    • height: height of the viewport of playwright
  • The rest are the setting for MajsoulUnlocker.

Instructions

Main Screen

image

You can see that there are two flows here, usually the top one is the "Lobby" websocket flow, and the bottom one is the "Game" websocket flow which appears after you join a match.

Click on the bottom flow to start. (It can take a while, click once and wait, don't click it for multiple times)

Flow Screen

image

After you are in the Flow Screen, this is what you should see. On top left is the LiqiProto Message we captured using MITM. The LiqiProto Message is then transcribe to mjai format and send to the bot(AI).

On top right is the MJAI Messages, this is the message our bot sent back to us, indicating the action we should do.

Then below is our tehai, it is composed using unicode characters.

Bottom left is the settings.

Bottom right is the bot's action.

How to keep your account safe

Following guide can minimum the probility of account suspension.

  1. Don't use steam, use web instead.
  2. Use safe_code.js from Majsoul Mod Plus
  3. Don't use MajsoulUnlocker as it modifies websocket.
  4. Don't use autoplay, play it yourself.
  5. Try to use stickers often.
  6. Don't completely follow what bot told you to do.
  7. Don't play 24hr a day using autoplay.

There is no way to guarantee 100% no account suspension currently.

TODO

  • 3 Player Mahjong
    • Already done, but not planned to release yet.
  • Change Setting inside application.
  • Autoplay
    • Auto use stickers to make opponent think we are not a bot.
    • Add random time in settings.json to let user choose time they want.
  • Mix multiple AI's decision to make we more like a human but not a perfect bot.
  • Reduce Startup time of the bot. (Maybe start it before match begin?)
  • Intergrade with MajsoulUnlocker
  • Don't use MITM at all for the gameplay, use image recognition.
    • Decide use what model
    • Training data generation
    • Train it
    • Delta Score Recognition.
    • Ryukyoku Recognition.
    • Implement
  • Easier installation.

Need Help!

  1. Any PR is welcomed.
  2. Tell me if the MajsoulUnlocker is working well, is there any trace about we modified the message leaked to Majsoul server?
  3. A stable and safe way to autoplay.
  4. Report any bug you encounter.
  5. Share your bot.zip if it is good.

Authors

Support me

Donating is optional, and the full functionality of this program is avaliable even without a donation.

ETH Mainnet: 0x83095C4355E43bDFe9cEf2e439F371900664D41F

Paypal or Others: Contact me on Discord.

You can find me at Discord.

What can I get after donating?

Firstly, thank you very much for your willingness to support the author.

I will prioritize the opinions of donors, such as feature requests and bug fixes.

Next, you can find me on Discord, where I will assign you a donor role.

See Also

Special Thanks

Equim-chan/Mortal

Majsoul Mod Plus

mahjong-helper

MahjongRepository/mahjong_soul_api

smly/mjai.app

LICENSE

“Commons Clause” License Condition v1.0

The Software is provided to you by the Licensor under the License, as defined below, subject to the following condition.

Without limiting other conditions in the License, the grant of rights under the License will not include, and the License does not grant to you, the right to Sell the Software.

For purposes of the foregoing, “Sell” means practicing any or all of the rights granted to you under the License to provide to third parties, for a fee or other consideration (including without limitation fees for hosting or consulting/ support services related to the Software), a product or service whose value derives, entirely or substantially, from the functionality of the Software. Any license notice or attribution required by the License must also include this Commons Clause License Condition notice.

Software: Akagi

License: GNU Affero General Public License version 3 with Commons Clause

Licensor: shinkuan

akagi's People

Contributors

constellation39 avatar elainafanboy avatar iamyou avatar jch12138 avatar latorc avatar motoiro avatar shinkuan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

akagi's Issues

活动场问题

在某些不影响主要游戏规则的活动场(如宝牌狂热或龙之目玉),轮到自己当庄会存在读牌与autoplay失效,我不知道1.6版本是否修复了,如已修复请关闭
Desktop (please complete the following information):

  • OS: [Windows]
  • Browser [chrome]
  • Version [1.5.0]

macOS端安装时的python版本问题

Describe the bug
在macOS端进行安装时,反复遇到报错:”Python version is not in the acceptable range. Please install Python between 3.10 and 3.12.”

使用conda配置了3.10.0, 3.11.x, 3.12.x三个环境进行安装,都出现同样的报错。在安装结束后,文件夹下缺失mitm,并有如下报错:
image

To Reproduce
进行安装就会出现问题,在我的机器上稳定复现。
image
image

运行过程中报错

╭───────────────────────────────────────── Traceback (most recent call last) ──────────────────────────────────────────╮
│ E:\Akagi\client.py:470 in get_messages                                                                               │
│                                                                                                                      │
│   467 │   │   │   │   │   if liqi_msg['method'] == '.lq.FastTest.authGame' and liqi_msg['type'                       │
│   468 │   │   │   │   │   │   self.app.push_screen(FlowScreen(flow_id))                                              │
│   469 │   │   │   │   │   │   pass                                                                                   │
│ ❱ 470 │   │   │   │   │   mjai_msg = self.bridge[flow_id].input(self.four_mjai_client, liqi_ms                       │
│   471 │   │   │   │   │   if mjai_msg is not None:                                                                   │
│   472 │   │   │   │   │   │   if self.bridge[flow_id].reach and mjai_msg["type"] == "dahai":                         │
│   473 │   │   │   │   │   │   │   mjai_msg["type"] = "reach"                                                         │
│                                                                                                                      │
│ ╭───────────────────────────────────────────────────── locals ─────────────────────────────────────────────────────╮ │
│ │  flow_id = '2c6204bd-b88c-4796-bf76-eb7b4ab3c13a'                                                                │ │
│ │ liqi_msg = {                                                                                                     │ │
│ │            │   'id': -1,                                                                                         │ │
│ │            │   'type': <MsgType.Notify: 1>,                                                                      │ │
│ │            │   'method': '.lq.ActionPrototype',                                                                  │ │
│ │            │   'data': {                                                                                         │ │
│ │            │   │   'step': 12,                                                                                   │ │
│ │            │   │   'name': 'ActionDiscardTile',                                                                  │ │
│ │            │   │   'data': {                                                                                     │ │
│ │            │   │   │   'seat': 1,                                                                                │ │
│ │            │   │   │   'tile': '8s',                                                                             │ │
│ │            │   │   │   'moqie': True,                                                                            │ │
│ │            │   │   │   'isLiqi': False,                                                                          │ │
│ │            │   │   │   'zhenting': False,                                                                        │ │
│ │            │   │   │   'tingpais': [],                                                                           │ │
│ │            │   │   │   'doras': [],                                                                              │ │
│ │            │   │   │   'isWliqi': False,                                                                         │ │
│ │            │   │   │   'tileState': 0,                                                                           │ │
│ │            │   │   │   'revealed': False,                                                                        │ │
│ │            │   │   │   ... +2                                                                                    │ │
│ │            │   │   }                                                                                             │ │
│ │            │   }                                                                                                 │ │
│ │            }                                                                                                     │ │
│ │ messages = b'\x01\n\x13.lq.ActionPrototype\x12%\x08\x0c\x12\x11ActionDiscardTile\x1a\x0e\x95}ch^\xa7N\x9cu\xcb\… │ │
│ │ mjai_msg = None                                                                                                  │ │
│ │     self = Akagi(title='Akagi', classes={'-dark-mode'})                                                          │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │
│                                                                                                                      │
│ E:\Akagi\majsoul2mjai.py:208 in input                                                                                │
│                                                                                                                      │
│   205 │   │   │   │   │   │   self.my_tsumohai = "?"                                                                 │
│   206 │   │   │   │   │   else:                                                                                      │
│   207 │   │   │   │   │   │   self.my_tehais.append("?")                                                             │
│ ❱ 208 │   │   │   │   │   self.my_tehais.remove(pai)                                                                 │
│   209 │   │   │   │   │   self.my_tehais = sorted(self.my_tehais, key=cmp_to_key(compare_pai))                       │
│   210 │   │   │   # Reach                                                                                            │
│   211 │   │   │   if parse_msg['data']['name'] == 'ActionReach':                                                     │
│                                                                                                                      │
│ ╭──────────────────────────────────── locals ────────────────────────────────────╮                                   │
│ │       actor = 1                                                                │                                   │
│ │ mjai_client = [                                                                │                                   │
│ │               │   <mjai.player.MjaiPlayerClient object at 0x000001B6F9203C50>, │                                   │
│ │               │   <mjai.player.MjaiPlayerClient object at 0x000001B6F9203910>, │                                   │
│ │               │   <mjai.player.MjaiPlayerClient object at 0x000001B6F9200E90>, │                                   │
│ │               │   <mjai.player.MjaiPlayerClient object at 0x000001B6F9206E90>  │                                   │
│ │               ]                                                                │                                   │
│ │         pai = '8s'                                                             │                                   │
│ │   parse_msg = {                                                                │                                   │
│ │               │   'id': -1,                                                    │                                   │
│ │               │   'type': <MsgType.Notify: 1>,                                 │                                   │
│ │               │   'method': '.lq.ActionPrototype',                             │                                   │
│ │               │   'data': {                                                    │                                   │
│ │               │   │   'step': 12,                                              │                                   │
│ │               │   │   'name': 'ActionDiscardTile',                             │                                   │
│ │               │   │   'data': {                                                │                                   │
│ │               │   │   │   'seat': 1,                                           │                                   │
│ │               │   │   │   'tile': '8s',                                        │                                   │
│ │               │   │   │   'moqie': True,                                       │                                   │
│ │               │   │   │   'isLiqi': False,                                     │                                   │
│ │               │   │   │   'zhenting': False,                                   │                                   │
│ │               │   │   │   'tingpais': [],                                      │                                   │
│ │               │   │   │   'doras': [],                                         │                                   │
│ │               │   │   │   'isWliqi': False,                                    │                                   │
│ │               │   │   │   'tileState': 0,                                      │                                   │
│ │               │   │   │   'revealed': False,                                   │                                   │
│ │               │   │   │   ... +2                                               │                                   │
│ │               │   │   }                                                        │                                   │
│ │               │   }                                                            │                                   │
│ │               }                                                                │                                   │
│ │        self = <majsoul2mjai.MajsoulBridge object at 0x000001B6F9386910>        │                                   │
│ │   tsumogiri = True                                                             │                                   │
│ ╰────────────────────────────────────────────────────────────────────────────────╯                                   │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
ValueError: list.remove(x): x not in list

win11下频发,不知道原因,感觉可能是因为我把docker镜像目录迁移了所以不太稳定(?

你好,请问那个bot.zip在哪里呀,我没有在discord里找到

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

使用mitm自带的chrome加载游戏非常非常慢

进入游戏界面就要20-30分钟,进入对局常常卡在整理牌桌78%,要10-20分钟才能进入对局。很多贴图加载不出来,看起来像是网速很慢的样子。但是用我自己的浏览器就不会这样。请问这是怎么回事呢

Setup Issue: MJAI Not Responding To POST Requests

Describe the bug
I get this bug when starting a friendly game in web browser
image

I get a Remote Disconnection error on the terminal when entering a game.

I started up my own docker instances from akagi.log and I can do GET request with 200 OK. But the code always fails when attempting this POST request:

[{"type": "start_game", "id": 2}]

I cannot do POST requests to my docker instances with the above payload (and neither can the code in player.py react function.

I think the MJAI Server is not setup properly or something?

To Reproduce
Steps to reproduce the behavior:

  1. Run python mitm_playwright.py
  2. Run Proxifier
  3. Run python client.py
  4. Start a friendly game with AI bots

Expected behavior
The client.py terminal to show the normal screen reading information for the game.

Screenshots
Full Error:

image

Docker instances:

image

MITM Running correctly:

image

Proxifier setup:

image image

Web browser playing the game from playwright:

image

Desktop (please complete the following information):

  • OS: Windows
  • Browser: Chrome

Additional context
I debugged the problem to the following:

EngineRuntimeError

C:\Users\akgai\Akagi\mjai\player.py:218 in react │
│ │
│ 215 │ │ except requests.Timeout: │
│ 216 │ │ │ raise TimeoutExpired(self.player_id) │
│ 217 │ │ except Exception as e: │
│ ❱ 218 │ │ │ raise EngineRuntimeError(f"RuntimeError: {str(e)}", self.player_id) │
│ 219 │ │ │
│ 220 │ │ return outs │
│ 221 │
│ │
│ ╭───────────────────────────────────── locals ─────────────────────────────────────╮ │
│ │ events = '[{"type": "start_game", "id": 2}]' │ │
│ │ input_data = b'[{"type": "start_game", "id": 2}]' │ │
│ │ self = <mjai.player.MjaiPlayerClient object at 0x00000191C404EDD0> │ │
│ │ timeout_per_action = 100.0 │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────╯ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
EngineRuntimeError: ("RuntimeError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without
response'))", 2)

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.