V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
zictos
V2EX  ›  Python

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

  •  
  •   zictos · 267 天前 · 2864 次点击
    这是一个创建于 267 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

    30 条回复    2023-08-06 15:04:02 +08:00
    xausky
        1
    xausky  
       267 天前
    你写好我愿意测试,不仅是启动慢,更难受的是像《影之诗》这种游戏 PC 端要扫码登录,我真是艹了。
    codehz
        2
    codehz  
       267 天前 via iPhone
    suspend 也是各种 dll 注入方法的第一步,通常是第一个要查的)
    zictos
        3
    zictos  
    OP
       267 天前
    @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
        4
    ClericPy  
       267 天前
    网游啊... 网游大都长连接吧, suspend 以后不掉线吗
    zictos
        5
    zictos  
    OP
       267 天前
    @ClericPy #4 原神好像一般只需要重连一下,或者就像传送时切换地图一样稍微加载一下,除非有小更新才能慢一点,要下载一点小更新。一般如果你每次都重新启动,那比这种暂停后恢复要慢很多很多,好多资源都要加载。
    不过如果是那种要完全重新登录的网游,那确实不合适。
    whileFalse
        6
    whileFalse  
       267 天前
    网游的话会掉线,你这元神应该不算正经网游吧
    zictos
        7
    zictos  
    OP
       267 天前
    @whileFalse #6 反正也是要一直联网的,只是没那么严格,毕竟不像别的网游在一个地方可以有很多很多人。有些网游确实严格,稍微有几秒连不上网就要掉线并且还要重新登录,非常麻烦,不知道是为了什么考虑,难道是因为不这样做就比较难防止外挂?
    whileFalse
        8
    whileFalse  
       267 天前
    @zictos 消息发不出去,服务端和客户端的状态就不一致了啊……
    消息本身在通讯协议层可以重发几次,但是如果超过重发的限制,丢了的消息去哪儿给你找回来呢。
    zictos
        9
    zictos  
    OP
       267 天前
    @whileFalse #8 我觉得掉线本身也没指望能再发出什么消息,只是希望网络恢复后快速直接进入能玩的状态,而不是重新登录和加载各种资源。本质上主要还是看游戏公司,多人在线的网游,有些游戏可能几秒就掉线,有些可能会比较长的时间连不上网才掉线,而且不同的游戏的掉线的时间阈值差距可能还挺大的。几分钟才掉线的也正常,最多就是游戏界面不更新了,等到网络恢复就直接更新界面了,玩家不需要任何额外操作。
    u20237
        10
    u20237  
       266 天前
    游戏启动慢的原因是使用的框架/引擎不好(也有可能配置不当),写个游戏引擎比较实在
    GeruzoniAnsasu
        11
    GeruzoniAnsasu  
       266 天前
    @zictos 服务器也要为每个已登录用户维持状态的,客户端掉线了最好,赶紧踢出内存节省空间
    zictos
        12
    zictos  
    OP
       266 天前
    @u20237 #10 只要是比较大的游戏,启动肯定快不了。我主要是考虑电脑玩累了,可以在游戏中乱跑看一下风景,原神游戏中的各种颜色太鲜艳了,绿油油的草也特别多,感觉顿时整个视界都明亮了。而平时电脑浏览网页和写代码或者做其他事情,大部分时候颜色都是比较灰暗的。如果要我专门去启动游戏等待,我肯定不愿意,所以就有必要后台运行。


    @GeruzoniAnsasu #11 嗯。其实对游戏服务器更好,我一直不下线后台运行还更占用他们的资源,他们也占用我的 cpu 资源。我是切换到后台立刻暂停,如果频繁切换就频繁暂停和恢复,切换时过渡起来也感觉不到任何延迟,很流畅。不过如果发现频繁切换时存在问题的话也可以延迟一点,比如切换到后台 30 秒再暂停。
    qscasdqwezxc
        13
    qscasdqwezxc  
       266 天前 via Android
    不需要完全 suspend 你设置一个间隔反复 suspend resume 就行了
    游戏会掉帧但是还在运行 cpu 调好间隔就占百分之一不到
    我记得之前有个工具做这个的忘了叫啥了
    zictos
        14
    zictos  
    OP
       266 天前
    @qscasdqwezxc #13 原神长时间完全 suspend 好像也问题不大。你指的是间隔多少?我反正觉得只要 resume ,cpu 就会占用比较大了。比如暂停 5 分钟,然后恢复 10 秒让游戏连接一下,再暂停 5 分钟这样循环吗?不过这样反复操作可能更会引起游戏公司的注意,而我有时候即便电脑一直在使用,但可能几个小时都不会将游戏切换到前台,在这种情况下游戏公司应该会认为我的电脑系统已经进入睡眠或休眠状态了。
    dearmymy
        15
    dearmymy  
       266 天前
    你都附加他进程了。当然会视为作弊。
    所谓 tp 之类驱动保护首要做的就是把附加进程之类函数驱动级别 hook 。当你附加不上。
    游戏内部如果定时枚举自身模块,会突然发现一个位置模块。肯定给你报作弊
    zictos
        16
    zictos  
    OP
       266 天前
    @dearmymy #15 什么叫附加进程,操作进程肯定要指定进程的啊!哪怕你通过命令结束一个进程,也要指定进程名的。这个就是操作系统的功能,psutil 模块应该也是通过操作系统的 api 实现的。各种管理进程的软件都是可以对别的进程进行各种操作的,比如限制网速、禁止联网、修改 cpu 使用的核心、修改 cpu 优先级。
    这也就是 windows 的任务管理器中没有暂停进程的选项,要是有的话就正常了吧?不过 windows 任何管理器修改 cpu 优先级和核心的功能还是有的。
    怎么判断一个功能是否正常,应该取决于是否修改了游戏文件或者修改了游戏内存。而不是连管理一下进程都不行。另外是否正常也不取决于是否能手工,通过命令或者 api 管理也是正常的,命令和 api 也是给人用的。linux 也有这样的暂停进程的功能。
    cnbatch
        17
    cnbatch  
       266 天前
    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
        18
    u20237  
       266 天前
    这个 API 至少 10 年前就有人在用(NT 内核或汇编)。关键字 "句柄" (也可是 内存)。

    羡慕那些懂 win32 API 的程序员。
    Terminl
        19
    Terminl  
       266 天前
    这种情况不会视为作弊,重复连接游戏服务器会导致强制断开,强制关闭游戏或者弹出登入等等。不想影响性能可以考虑云游戏或者远程桌面
    crab
        20
    crab  
       266 天前
    以前玩泡泡堂,游戏识别到玩家最小化窗口也会优化成黑屏节约资源。
    Shatyuka
        21
    Shatyuka  
       266 天前 via iPhone
    感觉不如切大地图,会停止 3D 渲染
    murmur
        22
    murmur  
       266 天前
    没必要,我记得剑三切后台就是锁 30 帧停部分渲染,人家知道你要躲开
    qscasdqwezxc
        23
    qscasdqwezxc  
       266 天前 via Android
    暂停 10ms 运行 1ms 这样
    zictos
        24
    zictos  
    OP
       266 天前
    @cnbatch #17 你提供了 stackoverflow 链接中说了 windows 资源监视器中可以手动暂停进程,试了一下还真的可以,但好像不能恢复。
    zictos
        25
    zictos  
    OP
       266 天前
    @Terminl #19 原神不会强制关闭游戏或强制重新登录。哪怕你电脑进入睡眠状态了或者休眠了,之后恢复后游戏一般也会自动恢复
    zictos
        26
    zictos  
    OP
       266 天前
    @crab #20 如果游戏会这么做,那就最好了。不过如果后台依然很占资源就只能自己想办法了。

    @Shatyuka #21 原神一般打开物品栏或者打开地图,游戏中的战斗其实都会停止的,cpu 也会降低,但降低不了太多。这个应该重点是减少显卡的使用率。

    @murmur #22 剑三这种应该不能像原神一样快速恢复,锁 30 帧应该还是会有一定 cpu 占用的。另外非游戏也有用的,比如 pycharm 有时候在后台也会突然 cpu 变高,可以判断 pycharm 内是否有其他脚本在运行,如果没有就切换到后台 15-30 分钟后自动暂停。平时保持后台运行比较方便,除非能做到 1-3 秒就启动完成。电脑最理想的状态就是大部分时候保证 cpu 的可用率一直在 90%以上,这样平时真正要运行什么的时候就很快。
    zictos
        27
    zictos  
    OP
       266 天前
    @qscasdqwezxc #23
    试了一下这样游戏还能正常玩,只是稍微有一点点卡,cpu 没降多少。如果暂停 1s ,运行 1ms ,那 cpu 就大概只占 1%了。
    pid = 32933
    import psutil, time
    while True:
    psutil.Process(pid).suspend()
    time.sleep(0.01)
    psutil.Process(pid).resume()
    time.sleep(0.001)
    DeWjjj
        28
    DeWjjj  
       266 天前
    会掉线得,不行。
    zictos
        29
    zictos  
    OP
       266 天前
    @DeWjjj #28 可以试试 27 楼的方法,可能不会掉线,具体时间自己定,暂停 10ms 运行 1ms ,这样无限循环的话,我试了游戏还可以正常玩
    miaomiao888
        30
    miaomiao888  
       266 天前
    其實就是無響應,比如電腦性能太差也會自然發生,不會有問題
    在 GTA 送貨的時候如果被人攻擊立馬暫停進程十秒即可卡入單人戰局
    手動也可以,利用任務管理器暫停
    ?t=39
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3125 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 14:06 · PVG 22:06 · LAX 07:06 · JFK 10:06
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.