使用 Python 在游戏切换到后台后将游戏进程挂起(暂停)会被视为作弊吗?目的是节省 cpu 资源

2023-08-05 20:04:42 +08:00
 zictos

在 windows 上,假设游戏进程的 pid 是 1234 。

在 python 中执行 psutil.Process(1234).suspend()就可以挂起游戏进程,游戏就不会占用任何 cpu 了,声音也会自动静音。

当 python 判断到游戏切换到前台后,就执行 psutil.Process(1234).resume(),这样就可以快速恢复游戏进程。整个过程的话游戏的代码执行状态不会改变,内存数据也不会改变。

主要是有时候游戏启动太慢,所以想一直开启,又不想在后台运行时占用 cpu 资源,只让游戏在前台运行时快速恢复进程。其实很多比较占资源的程序都可以这么操作,相当于将程序切换到后台后就让程序进入睡眠状态了。我感觉对于游戏公司来说,这样做应该就跟电脑进入了睡眠状态之后再唤醒差不多。

3248 次点击
所在节点    Python
30 条回复
xausky
2023-08-05 20:08:04 +08:00
你写好我愿意测试,不仅是启动慢,更难受的是像《影之诗》这种游戏 PC 端要扫码登录,我真是艹了。
codehz
2023-08-05 20:17:07 +08:00
suspend 也是各种 dll 注入方法的第一步,通常是第一个要查的)
zictos
2023-08-05 20:21:17 +08:00
@xausky #1
下面是原神的,将****替换成四空格就行。我是根据以前的代码改的,所以中间有些条件可能是多余的,因为我切换到后台暂停了一次,切换到后台 30 秒后又暂停了一次,我之前是 30 秒后要做的事情不一样。并且暂停之后只要没有再将原神切换到前台,那么就一直不再次暂停,防止反复操作。


import time, os
import win32process, win32gui
import psutil
import win32com.client


def get_yuanshen_pid():
****try:
********process_name = 'YuanShen.exe'
********WMI = win32com.client.GetObject('winmgmts:')
********processes = WMI.InstancesOf('Win32_Process')
********pid = next((process.ProcessId for process in processes if process.Name.lower() == process_name.lower()), None)
********if isinstance(pid, int):
************return pid
********else:
************return None
****except:
********return None


# 如果刚启动脚本后发现已经暂停就先恢复,有时候要是暂停了多次可能要恢复多次。
pid = get_yuanshen_pid()
if pid:
****for i in range(5):
********psutil.Process(pid).resume()

last_process_name = ''
last_yuanshen_time = 0
paused = False

while True:
****try:
********handle = win32gui.GetForegroundWindow()
********pid = win32process.GetWindowThreadProcessId(handle)[1]
********process_name = psutil.Process(pid).name()
********last = last_process_name
********last_process_name = process_name
********if process_name != last:
************if process_name == 'dwm.exe': #将已暂停程序切换到前台,windows 检测到的前台程序是 dwm.exe
****************pid = get_yuanshen_pid()
****************if pid:
********************psutil.Process(pid).resume()
********************paused = False
************elif process_name != 'YuanShen.exe' and last_yuanshen_time != 0:
****************pid = get_yuanshen_pid()
****************if pid and not paused:
********************psutil.Process(pid).suspend()
********************paused = True

********if process_name == 'YuanShen.exe':
************last_yuanshen_time = int(time.time())
********elif int(time.time()) - last_yuanshen_time > 30 and last_yuanshen_time != 0:
************pid = get_yuanshen_pid()
************if pid and not paused:
****************psutil.Process(pid).suspend()
****************paused = True
************last_yuanshen_time = 0
********time.sleep(1)
****except BaseException as e:
********print(e)
********time.sleep(1)
ClericPy
2023-08-05 20:59:53 +08:00
网游啊... 网游大都长连接吧, suspend 以后不掉线吗
zictos
2023-08-05 21:06:21 +08:00
@ClericPy #4 原神好像一般只需要重连一下,或者就像传送时切换地图一样稍微加载一下,除非有小更新才能慢一点,要下载一点小更新。一般如果你每次都重新启动,那比这种暂停后恢复要慢很多很多,好多资源都要加载。
不过如果是那种要完全重新登录的网游,那确实不合适。
whileFalse
2023-08-05 21:10:39 +08:00
网游的话会掉线,你这元神应该不算正经网游吧
zictos
2023-08-05 21:16:24 +08:00
@whileFalse #6 反正也是要一直联网的,只是没那么严格,毕竟不像别的网游在一个地方可以有很多很多人。有些网游确实严格,稍微有几秒连不上网就要掉线并且还要重新登录,非常麻烦,不知道是为了什么考虑,难道是因为不这样做就比较难防止外挂?
whileFalse
2023-08-05 21:22:18 +08:00
@zictos 消息发不出去,服务端和客户端的状态就不一致了啊……
消息本身在通讯协议层可以重发几次,但是如果超过重发的限制,丢了的消息去哪儿给你找回来呢。
zictos
2023-08-05 21:39:32 +08:00
@whileFalse #8 我觉得掉线本身也没指望能再发出什么消息,只是希望网络恢复后快速直接进入能玩的状态,而不是重新登录和加载各种资源。本质上主要还是看游戏公司,多人在线的网游,有些游戏可能几秒就掉线,有些可能会比较长的时间连不上网才掉线,而且不同的游戏的掉线的时间阈值差距可能还挺大的。几分钟才掉线的也正常,最多就是游戏界面不更新了,等到网络恢复就直接更新界面了,玩家不需要任何额外操作。
u20237
2023-08-05 22:38:37 +08:00
游戏启动慢的原因是使用的框架/引擎不好(也有可能配置不当),写个游戏引擎比较实在
GeruzoniAnsasu
2023-08-05 22:41:27 +08:00
@zictos 服务器也要为每个已登录用户维持状态的,客户端掉线了最好,赶紧踢出内存节省空间
zictos
2023-08-05 22:50:50 +08:00
@u20237 #10 只要是比较大的游戏,启动肯定快不了。我主要是考虑电脑玩累了,可以在游戏中乱跑看一下风景,原神游戏中的各种颜色太鲜艳了,绿油油的草也特别多,感觉顿时整个视界都明亮了。而平时电脑浏览网页和写代码或者做其他事情,大部分时候颜色都是比较灰暗的。如果要我专门去启动游戏等待,我肯定不愿意,所以就有必要后台运行。


@GeruzoniAnsasu #11 嗯。其实对游戏服务器更好,我一直不下线后台运行还更占用他们的资源,他们也占用我的 cpu 资源。我是切换到后台立刻暂停,如果频繁切换就频繁暂停和恢复,切换时过渡起来也感觉不到任何延迟,很流畅。不过如果发现频繁切换时存在问题的话也可以延迟一点,比如切换到后台 30 秒再暂停。
qscasdqwezxc
2023-08-05 23:30:30 +08:00
不需要完全 suspend 你设置一个间隔反复 suspend resume 就行了
游戏会掉帧但是还在运行 cpu 调好间隔就占百分之一不到
我记得之前有个工具做这个的忘了叫啥了
zictos
2023-08-05 23:40:05 +08:00
@qscasdqwezxc #13 原神长时间完全 suspend 好像也问题不大。你指的是间隔多少?我反正觉得只要 resume ,cpu 就会占用比较大了。比如暂停 5 分钟,然后恢复 10 秒让游戏连接一下,再暂停 5 分钟这样循环吗?不过这样反复操作可能更会引起游戏公司的注意,而我有时候即便电脑一直在使用,但可能几个小时都不会将游戏切换到前台,在这种情况下游戏公司应该会认为我的电脑系统已经进入睡眠或休眠状态了。
dearmymy
2023-08-05 23:59:02 +08:00
你都附加他进程了。当然会视为作弊。
所谓 tp 之类驱动保护首要做的就是把附加进程之类函数驱动级别 hook 。当你附加不上。
游戏内部如果定时枚举自身模块,会突然发现一个位置模块。肯定给你报作弊
zictos
2023-08-06 00:13:51 +08:00
@dearmymy #15 什么叫附加进程,操作进程肯定要指定进程的啊!哪怕你通过命令结束一个进程,也要指定进程名的。这个就是操作系统的功能,psutil 模块应该也是通过操作系统的 api 实现的。各种管理进程的软件都是可以对别的进程进行各种操作的,比如限制网速、禁止联网、修改 cpu 使用的核心、修改 cpu 优先级。
这也就是 windows 的任务管理器中没有暂停进程的选项,要是有的话就正常了吧?不过 windows 任何管理器修改 cpu 优先级和核心的功能还是有的。
怎么判断一个功能是否正常,应该取决于是否修改了游戏文件或者修改了游戏内存。而不是连管理一下进程都不行。另外是否正常也不取决于是否能手工,通过命令或者 api 管理也是正常的,命令和 api 也是给人用的。linux 也有这样的暂停进程的功能。
cnbatch
2023-08-06 00:56:42 +08:00
Windows 暂停进程有 3 种办法:
(参考 https://stackoverflow.com/questions/11010165/how-to-suspend-resume-a-process-in-windows
1. 手动暂停目标程序所有线程(重新恢复时可能会导致目标进程的线程死锁)
2. 使用未文档化的内部 API
3. 调试器模式(需要附加进程)

其中 psutil 用的是第二种,使用未文档化的内部 API:NtSuspendProcess 和 NtResumeProcess
https://github.com/giampaolo/psutil/blob/master/psutil/_psutil_windows.c

至于这两个 API 是怎么做的,有没有什么副作用,没人知道,微软没说。
“未文档化的 API”另一个称呼叫做“未记载的 API”,意思是,这是微软内部给自己用的,暂时不打算放出去给别人用,有可能以后就删了,或者哪个时刻改了内部实现模式也说不定。

所以会不会被判断为作弊,只有实际试了才知道
u20237
2023-08-06 01:23:19 +08:00
这个 API 至少 10 年前就有人在用(NT 内核或汇编)。关键字 "句柄" (也可是 内存)。

羡慕那些懂 win32 API 的程序员。
Terminl
2023-08-06 01:36:21 +08:00
这种情况不会视为作弊,重复连接游戏服务器会导致强制断开,强制关闭游戏或者弹出登入等等。不想影响性能可以考虑云游戏或者远程桌面
crab
2023-08-06 03:11:47 +08:00
以前玩泡泡堂,游戏识别到玩家最小化窗口也会优化成黑屏节约资源。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/962671

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX