apricot-s / majsoulrpa Goto Github PK
View Code? Open in Web Editor NEWA Robotic Process Automation (RPA) framework for Mahjong Soul (雀魂)
License: Other
A Robotic Process Automation (RPA) framework for Mahjong Soul (雀魂)
License: Other
HomePresentation.join_room
の戻り値の型は bool
ですが,これだと False
が返ってきたときに
のどれが原因で部屋への join が失敗したかが分からないです.上記3つはゲーム画面上のエラーメッセージとしては区別されているため, API を調べれば区別できる可能性が高いと思います(要調査).これが区別できるように join_room
を拡張してほしいです.
メールアドレスの形式が間違っていても
正しいときと同様のボタンの表示待ち・タイムアウトが発生する。
また、メールアドレスの再入力ができないため、
メールアドレスの形式は正しいがtypoがあった場合に再入力できない。
(参考: メールアドレス欄の最大入力可能文字数は半角全角合わせて50文字までである。)
現在get_config()は[authentication]欄の内容が必須だが、
RPAクラスのインスタンス生成には不要なのでオプションにしたい
please&thank u
詳細な導入ドキュメントまたはインストール手順を送っていただけますか?
majsoulrpa_remote_browser
コマンドを実行すると ModuleNotFoundError
例外が送出される
python3 -m pip .
でインストール後, majsoulrpa_remote_browser
コマンドを実行する.
以下の例外が送出されてコマンドの実行が終了する.
Traceback (most recent call last):
File "C:\Users\Cryolite\Documents\work\majsoulrpa\.venv\Scripts\\majsoulrpa_remote_browser", line 3, in <module>
from src.majsoulrpa.remote_browser._remote_browser import main
ModuleNotFoundError: No module named 'src'
リモートブラウザが正常に起動する.
各Presentationは現在_impl
の
BrowserBase
, MessageQueueClientBase
, PresentationCreatorBase
をメンバーに持っているが、できればRPA
をメンバーに持つようにする
ただし、RPA
のプライベートメンバーへのアクセスを避けつつ外部には非公開にする必要がある(要設計)
RPA.wait
からしかPresentationBase
を受け取れず、自分で生成できないRPA.close()
にてBrowserBase
, MessageQueueClientBase
を終了してもPresentationからの参照が残っているため_impl
のクラスの__del__
が呼ばれないPresentationクラスの__init__
に_impl
のクラスではなくRPA
クラスを与える
RPA
はPresentationに各メンバーを公開する手段を持つ(フレームワーク利用者には非公開にする)
開発方針と注意事項をREADMEに明記する
許可のとれた身内での大会戦・友人戦に麻雀AIを参加させる等を想定している
段位戦参加機能は開発しない(プルリクが来てもrejectする)
利用して運営からBANされるリスクなどの責任はとれないことを明記する
イベント期間中は対局後イベントアイテムを獲得することがある。
獲得後次の画面に進むためには画面をクリックする必要があるが、現在対応していないので対処する。
イベントアイテムを獲得したとき
イベント期間中の対局後にイベントアイテムを獲得したとき、
アイテムを獲得した後の画面から次の画面(友人戦部屋など)に遷移しない。
イベント期間中の対局後にイベントアイテムを獲得した場合も正常に次の画面に遷移する。
コードにnoqaが散らばっているので設定頻度が多いものに関しては
pyproject.tomlに一括で設定する
・C901 → リファクタリング箇所の参考にするため一旦保留とする
・PLRの一部
・init.pyのF401 → 代わりに__all__を設定する
毎朝6時にはクエスト更新やショップの更新などの通知メッセージがあります。そのため試合が6時をまたがって行われた場合、以下のメッセージを受け取ります。
('inbound', '.lq.NotifyActivityTaskUpdate', {'progresses': ...})
('outbound', '.lq.Lobby.fetchShopInterval', ...)
MatchPresentation では対応できていないためエラーとなります。
_on_end_of_match()
などのメッセージを dequeue する処理において、上述したメッセージを dequeue してもエラーが発生しないよう修正する必要があります。
大会戦に参加することができるようにする
リモートブラウザを起動しようとすると net::ERR_PROXY_CONNECTION_FAILED
例外が送出される場合がある.
リモートブラウザの起動を試みる.ただし,タイミングに関するバグと推測されるため,必ずしも再現されるとは限らない.
リモートブラウザの起動に関する実装において, sniffer プロセスの起動直後にブラウザを起動している.
majsoulrpa/src/majsoulrpa/remote_browser/_remote_browser.py
Lines 198 to 213 in d5dfe44
この結果, sniffer プロセスがプロキシポートの listen を開始する前にブラウザがプロキシポートに接続しようとする可能性がある.この場合,プロキシポートがまだ開いていないため,ブラウザがプロキシに接続できず net::ERR_PROXY_CONNECTION_FAILED
例外を送出するものと推測される.
以下の例外が送出される.
Traceback (most recent call last):
File "/root/majsoulrpa/.venv/bin/majsoulrpa_remote_browser", line 8, in <module>
sys.exit(main())
^^^^^^
File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/majsoulrpa/remote_browser/_remote_browser.py", line 252, in main
launch_remote_browser(
File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/majsoulrpa/remote_browser/_remote_browser.py", line 226, in launch_remote_browser
_launch_remote_browser_core(
File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/majsoulrpa/remote_browser/_remote_browser.py", line 75, in _launch_remote_browser_core
page.goto(URL_MAJSOUL)
File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/playwright/sync_api/_generated.py", line 9312, in goto
self._sync(
File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/playwright/_impl/_sync_base.py", line 115, in _sync
return task.result()
^^^^^^^^^^^^^
File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/playwright/_impl/_page.py", line 475, in goto
return await self._main_frame.goto(**locals_to_params(locals()))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/playwright/_impl/_frame.py", line 139, in goto
await self._channel.send("goto", locals_to_params(locals()))
File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/playwright/_impl/_connection.py", line 62, in send
return await self._connection.wrap_api_call(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/playwright/_impl/_connection.py", line 492, in wrap_api_call
return await cb()
^^^^^^^^^^
File "/root/majsoulrpa/.venv/lib/python3.12/site-packages/playwright/_impl/_connection.py", line 100, in inner_send
result = next(iter(done)).result()
^^^^^^^^^^^^^^^^^^^^^^^^^
playwright._impl._errors.Error: net::ERR_PROXY_CONNECTION_FAILED at https://game.mahjongsoul.com/
リモートブラウザが正常に起動する.
ローカルブラウザではuser_data_dir
の指定によってプロファイルを保存でき、
2回目以降の起動ではメールアドレス経由の認証を省略できる。
リモートブラウザでも同じ動作ができるようにする
launch_remote_browser
関数、majsoulrpa_remote_browser
コマンドにuser_data_dir
を指定可能にする
READMEにフレームワークに必要なソフトウェアが書かれていないので追記する
オリジナル同様Prerequisitesがある
大会に入室した際、新しい API .lq.Lobby.fetchManagerCustomizedContestList
がやり取りされた。
現在 majsoulrpa に同梱している liqi_pb2.py に入っていないため、 liqi_pb2.py の更新およびメッセージ処理の追加が必要である。
examples\enter_tournament.py
(前略)
INFO:majsoulrpa.presentation.home:('outbound', '.lq.Lobby.loginSuccess', {}, {}, datetime.datetime(2024, 7, 24, 9, 30, 10, 983251, tzinfo=datetime.timezone.utc))
INFO:majsoulrpa.presentation.home:('outbound', '.lq.Lobby.heatbeat', {'no_operation_counter': 0}, {'error': {'code': 0, 'u32_params': [], 'str_params': [], 'json_param': ''}}, datetime.datetime(2024, 7, 24, 9, 30, 11, 390945, tzinfo=datetime.timezone.utc))
INFO:majsoulrpa.presentation.home:('outbound', '.lq.Lobby.heatbeat', {'no_operation_counter': 0}, {'error': {'code': 0, 'u32_params': [], 'str_params': [], 'json_param': ''}}, datetime.datetime(2024, 7, 24, 9, 30, 12, 542528, tzinfo=datetime.timezone.utc))
INFO:majsoulrpa.presentation.home:('outbound', '.lq.Lobby.loginBeat', {'contract': 'DF2vkXCnfeXp4WoGSBGNcJBufZiMN3UP'}, {}, datetime.datetime(2024, 7, 24, 9, 30, 12, 793821, tzinfo=datetime.timezone.utc))
INFO:majsoulrpa.presentation.home:('outbound', '.lq.Lobby.loginBeat', {'contract': 'DF2vkXCnfeXp4WoGSBGNcJBufZiMN3UP'}, {}, datetime.datetime(2024, 7, 24, 9, 30, 12, 823415, tzinfo=datetime.timezone.utc))
INFO:majsoulrpa.presentation.home:('outbound', '.lq.Lobby.heatbeat', {'no_operation_counter': 0}, {'error': {'code': 0, 'u32_params': [], 'str_params': [], 'json_param': ''}}, datetime.datetime(2024, 7, 24, 9, 30, 16, 452128, tzinfo=datetime.timezone.utc))
Tournament ID: 000000
INFO:majsoulrpa.presentation.home:('outbound', '.lq.Lobby.heatbeat', {'no_operation_counter': 0}, {'error': {'code': 0, 'u32_params': [], 'str_params': [], 'json_param': ''}}, datetime.datetime(2024, 7, 24, 9, 30, 20, 460244, tzinfo=datetime.timezone.utc))
Traceback (most recent call last):
File "C:\Users\K_K\Documents\Program\mahjong\majsoulrpa\src\majsoulrpa\_impl\zmq_client.py", line 124, in jsonize
parser = self._message_type_map[name][0]()
~~~~~~~~~~~~~~~~~~~~~~^^^^^^
KeyError: '.lq.Lobby.fetchManagerCustomizedContestList'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:\Users\xxx\Documents\Program\mahjong\majsoulrpa\examples\enter_tournament.py", line 61, in <module>
presentation.enter_tournament(tournament_id)
File "C:\Users\xxx\Documents\Program\mahjong\majsoulrpa\src\majsoulrpa\presentation\home.py", line 504, in enter_tournament
message = self._message_queue_client.dequeue_message(1)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\xxx\Documents\Program\mahjong\majsoulrpa\src\majsoulrpa\_impl\zmq_client.py", line 147, in dequeue_message
jsonized_request = jsonize(name, request_data, is_response=False)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\xxx\Documents\Program\mahjong\majsoulrpa\src\majsoulrpa\_impl\zmq_client.py", line 137, in jsonize
raise RuntimeError(msg) from ke
RuntimeError: A new API found:
name: .lq.Lobby.fetchManagerCustomizedContestList
Raw data was saved to 2024-07-24-09-30-28-.lq.Lobby.fetchManagerCustomizedContestList.bin.
Please cooperate by providing data. Thank you for your cooperation.
バイナリのため Hex Editor で表示した内容を添付する
0A 02 6A 70
大明槓がロンで妨害されたときの処理を追加する
現在はスクリーンショットを保存した後UnexpectedStateErrorを投げる
ポンのときと同様の処理を行う
RPA と Presentation が循環参照になっている
設計の観点からも RPA.wait() は本来 presentation モジュール側のクラスのメソッドかトップレベルの関数になると思われる
Presentation*** の import を RPA.wait() メソッド内まで遅延させて循環インポートを回避している
RPA.wait() に相当するトップレベルの関数もしくは別クラスのメソッドを作成する
RPA.wait() を削除する (しばらくは非推奨の警告を出しつつ残す)
認証コードの入力が間違っていても
入力が正しいときと同様のボタンの表示待ち・タイムアウトが発生する。
認証コードの形式(半角数字6桁)が誤っていた場合は画面に入力せずにValueErrorを投げる
認証コードが誤っていた場合「確認」をクリック後「ログイン」をクリックして認証画面に戻ってからValueErrorを投げる
Tested on Windows 11, Python 3.11.
When user_data_dir
is set to a value in the config.toml
, the data is saved at wrong location.
Example of config.toml
:
[browser]
user_data_dir = "./user_data" # User data directory (comment out this line to use incognito mode).
Expected:
A dir called user_data appear at the execute location and the data is in there.
What Happened:
A dir called user_data appear at the execute location but data is not saved there.
Instead, it saved "./user_data" to <location of playwright installed>/user_data
protocはZMQClient
が未知のAPIを受け取ったとき、エラーメッセージにデコードしたAPIを表示するためだけに必要である
未知のAPIに対応するには新しいliqi.jsonからliqi_pb2.pyを作成して差し替えるしかないため、
ユーザーにとってはエラーメッセージを表示する必要性は薄い
稀な事象でのスクショと同様に、バイナリ(bytes)の生データをそのままバイナリファイルに保存するだけでいいと思われる
その場合、ユーザーがインストールするソフトウェアを減らすことができる
ZMQClient
が未知のAPIを受け取ったとき、
protocを使用してWebSocketメッセージをデコードし、その結果をエラーメッセージとして表示する
そのためにユーザーはprotocのインストールが必要となる
ZMQClient
が未知のAPIを受け取ったとき、
WebSocketメッセージのバイナリをそのままファイルに保存する
ユーザーはprotocをインストールする必要がない
リモートモードでRPAの接続先のリモートブラウザがないとき固まる
・タイムアウトを過ぎても処理が終了しない
・Ctrl+cが効かない
Loginの__init__内で止まっている
majsoulrpa_remote_browserが起動していない状態で
リモートモードのRPAを起動し、RPA.wait()を実行する
リモートモードでRPAの接続先のリモートブラウザがないときも
・タイムアウトを過ぎるとTimeoutErrorを投げる
・Ctrl+cを入力するとKeyboardinterruptを投げる
EN版、CN版に対応する
各国語版の違い
JP版のみ対応している
JP版、CN版(中文(简体)、中文(繫體))、EN版(English、中文(繁體)、한국어)に対応する
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.