Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi-Client Detection and NoLeagueClientDetected Exception Handling #39

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

WordlessMeteor
Copy link

I've used your library for more than two years, and it's really easy to grasp, since my coding background is mainly in Python, and someone has built a code frame to inherit easily. However, I did find something to improve, which I couldn't achieve without changing these library files.
First is the multi-client detection. In the 3.0.0 version, once lcu-driver captures a wanted League Client process, it'll directly decide to communicate with that client, without check if there's any other running clients. Sometimes the user may want to operate multiple clients by LCU API operations, but it seems the 3.0.0 version can't achieve this.
The other idea is a BUG fix. I conclude from my experience that lcu-driver library code produce an infinite loop when no client is running. By setting the upper limit of times to retry finding League Client process, lcu-driver will give definite prompts about whether there's a client running, and it won't take too long to finish the retrying process.
These changes turn out to be operating well on my PC. I'd apprecaite it if you could take my opinions into consideration.

…Prompts on Absence of Any Running Client】

一、库文件更新综述(Library File Update Summary)
lcu-driver库是本人唯一使用过的调用LCU API的工具。借助一位知乎用户的框架,自己写了很多用于实现各种小功能的脚本。不过,在使用的过程中,本人发现,当一台设备运行多个英雄联盟客户端时(同时运行国服和美服,或者拳头代理的英雄联盟英雄联盟客户端多开),通过这个库只能与先运行的英雄联盟客户端取得通讯(我也不太确定是不是先运行的那个能取得通讯,但反正就是只能与其中一个取得通讯),而无法与第二个、第三个以及后面的英雄联盟客户端取得通讯。因此,本次更新的主要目标就是,通过修改lcu-driver库的代码,使得在用户使用lcu-driver库执行任何操作之前,lcu-driver库的代码都会提示用户选择一个英雄联盟客户端进行通讯。当然,在一个程序的一次生命周期内,只允许与一个英雄联盟客户端取得通讯。除非这个用户开了多个命令提示符窗口,然后分别选择与不同的英雄联盟客户端取得通讯。
`lcu-driver` library has been the only tool for me to call LCU API. With the frame provided by a ZhiHu author (XHXIAIEIN), I wrote many tiny scripts to implement some functions. However, while coding with this library, I found that when there're multiple League Clients running on a device (e.g. running TENCENT LoL and Riot LoL at the same time or Riot LoL multi-client), this library only provides access to the first launched League Client (I'm not sure if it's the first launched League Client that is accessible, but anyway there's only one accessible League Client). There's curently no way to communicate with the second, the third, and even later launched League Clients. Hence, the main aim of this update is to modify the code of `lcu-driver` library, so that before a user do anything using `lcu-driver` library, he/she has to select a League Client to communicate with according to the prompts generated by the updated `lcu-driver` library code. Of course, during a life cycle, the user can only communicate with one League Client, unless he/she opens multiple CMD windows/tabs and selects different League Clients to communicate with, respectively.
另外,在使用的过程中,本人还注意到,如果一个用户在未运行任何英雄联盟客户端的时候运行基于lcu-driver库的程序,那么程序将会一直卡在lcu-driver库寻找英雄联盟客户端的环节,直到用户运行某个英雄联盟客户端,然后程序与该英雄联盟客户端取得通讯。在本次更新中,lcu-driver库将会正确地提示用户无英雄联盟客户端运行,这样用户能够更加明确地决定下一步的操作。毕竟,这样总比程序一直卡在一个环节毫无提示要好吧。
What's more, I noticed that if a user runs any program based on `lcu-driver` library, but hasn't launched any League Client, then the program will stuck at `lcu-driver`'s searching for League Client, until the user launches a League Client, when the program finally gets access to this client. In this update, `lcu-driver` library will remind the user that there's currently no League Client running, so that the user can more definitely decide on his/her next operation. This would be better than a program stucking at some unknown stage without any printed prompts, after all.
二、实现细节(Implementation Details)
实际上,本次更新的大部分代码不是在实现这两个功能,而是专注于多英雄联盟客户端信息输出的排版。因此,需要将功能的实现和输出的排版这两部分代码分开来叙述。
As a matter of fact, a great part of code are focused on typesetting the output of multiple League Clients' information, rather than the implementation of the two functions. Therefore, the implementation of functions and the typesetting of output will be illustrated in two parts.
(一)功能更新(Functional Update)
1. 添加了列表变量process_iter,用来存储多个英雄联盟客户端进程变量。(connector.py第63行。)
Added a list variable `process_iter` to store multiple League Client process variable. (Line 63 in `connector.py`.)
2. 修改了_return_ux_process函数的参数表。现在,该函数多出了一个列表类型的默认参数processList。如果调用该函数时不向该函数传入任何参数,那么该参数默认为空列表。(utils.py第15行和connector.py第66行。)
Modified the parameter list of `_return_ux_process` function. Now, there's a default parameter `processList` of list type. If no parameter is passed to this function, then this parameter is an empty list by default. (Line 15 in `utils.py` and Line 66 in `connector.py`.)
3. 修改了_return_ux_process函数的函数体。现在,该函数只会在遇到检测到新的英雄联盟客户端进程时,才会返回该进程。(utils.py第17行。)
Changed the body of `_return_ux_process` function. Now, this function only returns a new League Client process. (Line 17 in `utils.py`.)
4. 只有当一个进程process不在列表变量process_iter中的时候,英雄联盟客户端进程列表process_iter才会追加该进程。(connector.py第66~68行。)
Only when a `process` isn't already in the list variable `process_iter`, the `process` will be appended to `process_iter` list. (Lines 66~68 in `connector.py`.)
5. 添加了NoLeagueClientDetected异常类,作为BaseException的子类。当未检测到英雄联盟客户端运行时,将抛出该异常。(exceptions.py第24和25行和connector.py第10和98行。)
Added an exception class `NoLeagueClientDetected` as a subclass of `BaseException`. This exception is raised when no running League Client is detected. (Lines 24 and 25 in `exceptions.py` and Lines 10 and 98 in `connector.py`.)
6. 移除了STATUS_ZOMBIE模块,因为它的存在将导致当用户处于登录队列中时,程序将卡在一个循环的位置不动。这将导致前面5点功能更新全部失效。(utils.py原代码第3、17和18行。)
Removed `STATUS_ZOMBIE` module, because its existence causes the program to be stuck in a loop, when the user is in a queue to log into League Client. And this situation will nullify the previous 5 function updates. (Lines 3, 17 and 18 in the original code of `utils.py`.)
(二)质量更新(Quality Update)
1. 引入了unicodedata库和wcwidth库中的wcswidth函数,用于调整各字符串在输出时的宽度。(connector.py第4和5行。)
Imported `unicodedata` library and `wcswidth` function in `wcwidth` library to adjust the width of all strings to print. (Lines 4 and 5 in `connector.py`.)
2. 定义了count_nonASCII函数,用于统计一个字符串中占用命令行2个宽度单位的字符个数。(connector.py第59和60行。)
Defined a function `count_nonASCII` to count the number of characters that take up two width unit in CMD. (Lines 59 and 60 in `connector.py`.)
3. 设置了重新尝试获取英雄联盟客户端进程的次数retry的上限,以防lcu-driver库不停地尝试获取英雄联盟客户端进程信息。(connector.py第64、65和69行。)
Set a upper limit of the `retry` times to capture the League Client process, in case `lcu-driver` library would search for a League Client process constantly. (Lines 64, 65 and 69 in `connector.py`.)
4. 关于检测到的英雄联盟客户端进程数量进行了分类讨论。当检测到多个客户端时,更新后的lcu-driver库将输出这些客户端的信息,然后让用户选择与第几个客户端通讯;当只检测到一个客户端时,运行效果与更新前相同;当未检测到客户端时,根据第5点功能更新,现在lcu-driver库将提示用户未检测到运行中的英雄联盟客户端,而不是反复寻找英雄联盟客户端进程。(connector.py第70、95和97行。)
Discussed about the number of detecetd League Client processes. When multiple League Client are detected, the updated `lcu-driver` library will output the clients' information and then let the user decide which client to communicate. When only one League Client is detected, the execution procedure is the same as that before this update. When no running client is detected, according to the fifth functional update, now the `lcu-driver` library will remind the user of this situation, instead of searching for a League Client process constantly. (Lines 70, 95 and 97 in `connector.py`.)
5. 现在,在检测到多个英雄联盟客户端进程时,lcu-driver库将输出这些进程的信息。输出的格式为某一列所有的字符串在命令行的输出宽度加2,居中对齐。(connector.py第71~80行。)
Now, when multiple League Client processes are detected, the updated `lcu-driver` library will output these processes' information. For any information string, its output width is the maximum of the width of strings of the same column plus 2. And all strings are output centered. (Lines 71~80 in `connector.py`.)
格式参考了英雄联盟自定义脚本存储库的一次提交内容——整合文件的第2条更新。
The format change is based on a commit (WordlessMeteor/LoL-DIY-Programs@29a1922) of `LoL-DIY-Programs` repository: the second update of the consolidated file.
6. 现在,在检测到多个英雄联盟客户端进程时,lcu-driver库可以处理用户提交进程序号的输入异常。(connector.py第81~94行。)
Now, when multiple League Client processes are detected, the updated `lcu-driver` library can handle the input error when the user is going to submit the selected process number. (Lines 81~94 in `connector.py`.)
7. 当lcu-driver库只检测到一个英雄联盟客户端进程时,程序将默认获取进程列表的第一个元素,使得运行效果如同更新前。(connector.py第96行。)
When only one League Client process is detected, the program will pass the first element of the process list `process_iter` to connection. This is just the same as before this update. (Line 96 in `connector.py`.)
三、未来规划(Future Plan)
针对第5条质量更新,在下次更新中,将会定义一个用来排版打印数据框内容的函数,以使代码更加易懂(更加符合抽象的原则)。
For the fifth quality update, in the next update, a function to typeset the output of a dataframe's content will be defined, so that the code will become more understandable (which makes the code more in line with the principle of abstract).
详见该提交的第一条说明。(connector.py的全部改动。)
Refer to the first statement of the commit WordlessMeteor/LoL-DIY-Programs@a33cb6d for more details. (All changes in connector.py.)
@sousa-andre
Copy link
Owner

Hey, first of all, thank you for contributing!
Excluding the part of the prints in the middle of the code, I'm a little overwhelmed with the complexity of the code and I'm not figuring out why is most of the stuff needed (such as pandas).

@WordlessMeteor
Copy link
Author

WordlessMeteor commented Dec 24, 2023

Thanks for your consideration! Indeed, a great part of changes don't necessarily influence the program execution. They're just for the typesetting work. As for why Pandas is needed, I picked DataFrame as the data structure to store LeagueClientux.exe process information.
In addition, you may compare the biggest green part of code changes in the two commits in the appendix of the first conversation of this pull request. You may find that the biggest green part in the second commit is an encapsulation of that of the first commit - they're actually the same thing. In the second commit, a function is defined to typeset the output of process information onto any terminal window. And based on the DataFrame structure, I made the format_df function to typeset the output of any dataframe that include Chinese characters (or non-ASCII characters that take up more than 1 width unit in Command Prompt). It's actually a bonus.
The shutil library is only used to get the terminal size, so that the user may decide whether to display process in full or simplified manner. The difference of a simplified manner from a full manner is that the simplified manner may omit the long strings and print ellipsis (...) instead, while a full manner outputs all the information regardless of the cleaness of the output content.

由于最近退出或登出英雄联盟不会导致LeagueClientUx.exe完全结束,反复退出后将导致大量该进程存在。因此,临时将重试次数上调至100次。这将会影响英雄联盟自定义脚本存储库中所有脚本的启动速度。
Due to incomplete kill of LeagueClientUx.exe after exiting or signing out of League of Legends, repeated operations may result in dozens of such processes. Therefore, the times to retry getting  the processes have been increased to 100. This will increase the time for launching the customized programs in the LoL-DIY-Programs repository.
注:该现象仅存在于国际服。等到拳头官方修复该问题后,此提交将被撤回。
Note: This phenomenon only exists in Riot LoL. This commit will be reverted after Riot fixed this problem.
…ess Infomation】

现在,本存储库提供的lcu-diver库将从某个时刻的进程信息中搜索英雄联盟客户端进程,而不是反复获取某个进程的下一个进程。
Now, the `lcu-driver` library in this repository will search for League Client process in processes at a certain timestamp, instead of iteratively getting the successor of a process.
现在,当遇到多个进程时,如果用户不输入任何字符而直接回车,程序将会自动选择最近创建的英雄联盟客户端进程。
Now, when there're multiple processes, if the user presses enter without inputting any strings, then the program will automatically selects the recently created LeagueClientUx process.
需要说明,如果format_df函数没有添加第65行代码的话,则第128行代码(添加后)会报错。
Note that if the 65th code line isn't added, then an exception will be likely thrown from the 128th code line (after addition).
…esses】

完整报错如下:
The whole exception is as follows:
Traceback (most recent call last):
  File "C:\Users\19250\Desktop\英雄联盟自定义房间创建\Customized Program 09 - Get Game Mode Information.py", line 255, in <module>
    connector.start()
  File "C:\Users\19250\AppData\Local\Programs\Python\Python311\Lib\site-packages\lcu_driver\connector.py", line 157, in start
    wrapper()
  File "C:\Users\19250\AppData\Local\Programs\Python\Python311\Lib\site-packages\lcu_driver\connector.py", line 118, in wrapper
    process_dict["filePath"].append(process_iter[i].cmdline()[0])
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\19250\AppData\Local\Programs\Python\Python311\Lib\site-packages\psutil\__init__.py", line 702, in cmdline
    return self._proc.cmdline()
           ^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\19250\AppData\Local\Programs\Python\Python311\Lib\site-packages\psutil\_pswindows.py", line 697, in wrapper
    return fun(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\19250\AppData\Local\Programs\Python\Python311\Lib\site-packages\psutil\_pswindows.py", line 727, in wrapper
    raise AccessDenied(pid=self.pid, name=self._name, msg=msg)
psutil.AccessDenied: <function Process.cmdline at 0x000001AE2D4114E0> retried 33 times, converted to AccessDenied as it's still returning [WinError 299] 仅完成部分的 ReadProcessMemory 或 WriteProcessMemory 请求。: '(originated from ReadProcessMemory)' (pid=10428, name='LeagueClientUx.exe')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants