Python编写Alan Wake重制版修改器:线程无法按预期停止问题
方案一:用线程安全的停止信号精准控制线程
线程停不掉的核心原因是循环里没及时检测到停止指令,或者指令传递存在线程同步问题。用threading.Event()做停止信号是最稳妥的方式,它是线程安全的,能避免读写不同步的坑。
具体实现步骤
- 初始化核心变量
import threading import pymem import customtkinter as ctk # 替换成你实际获取的进程和内存地址 pm = pymem.Pymem("AlanWakeRemastered.exe") battery_addr = 0xXXXXXXX # 电池静态基址+偏移 revolver_ammo_addr = 0xXXXXXXX # 左轮弹药静态基址+偏移 # 每个作弊功能对应独立的停止信号和线程对象 battery_stop = threading.Event() battery_thread = None revolver_stop = threading.Event() revolver_thread = None
- 编写带停止检测的作弊循环
def keep_battery_full(): while not battery_stop.is_set(): try: pm.write_int(battery_addr, 100) # 写入满电池值 threading.Event().wait(0.1) # 加延迟降CPU占用 except: # 进程关闭或内存读写失败时直接退出循环 break # 线程结束后清空对象,避免重复启动 global battery_thread battery_thread = None def keep_revolver_ammo_full(): while not revolver_stop.is_set(): try: pm.write_int(revolver_ammo_addr, 999) threading.Event().wait(0.1) except: break global revolver_thread revolver_thread = None
- 复选框回调控制启停
def toggle_battery_cheat(): global battery_thread if battery_checkbox.get(): # 勾选时重置停止信号,启动新线程(先检查线程是否存活) battery_stop.clear() if not battery_thread or not battery_thread.is_alive(): battery_thread = threading.Thread(target=keep_battery_full, daemon=True) battery_thread.start() else: # 取消勾选时触发停止信号 battery_stop.set() def toggle_revolver_cheat(): global revolver_thread if revolver_checkbox.get(): revolver_stop.clear() if not revolver_thread or not revolver_thread.is_alive(): revolver_thread = threading.Thread(target=keep_revolver_ammo_full, daemon=True) revolver_thread.start() else: revolver_stop.set()
- GUI部分
app = ctk.CTk() battery_checkbox = ctk.CTkCheckBox(app, text="无限电池", command=toggle_battery_cheat) battery_checkbox.pack(pady=5) revolver_checkbox = ctk.CTkCheckBox(app, text="无限左轮弹药", command=toggle_revolver_cheat) revolver_checkbox.pack(pady=5) app.mainloop()
关键细节
- 用
daemon=True创建线程,主程序退出时线程会自动终止,不会残留后台进程 - 每次启动前检查线程状态,避免重复启动多个相同线程
- 循环里加
wait(0.1),防止线程无限制占用CPU资源 - 捕获异常,避免游戏进程关闭时修改器直接崩溃
方案二:用customtkinter原生
after()替代线程(新手友好) 如果对线程操作没信心,直接用GUI库自带的after()方法实现周期性任务,完全不会阻塞主线程,也不用处理线程同步问题。
具体实现步骤
- 初始化变量
import pymem import customtkinter as ctk pm = pymem.Pymem("AlanWakeRemastered.exe") battery_addr = 0xXXXXXXX revolver_ammo_addr = 0xXXXXXXX # 标记作弊功能是否激活 battery_active = False revolver_active = False
- 编写递归执行的作弊任务
def update_battery(): if battery_active: try: pm.write_int(battery_addr, 100) except: pass # 100ms后再次调用自己,实现循环执行 app.after(100, update_battery) def update_revolver_ammo(): if revolver_active: try: pm.write_int(revolver_ammo_addr, 999) except: pass app.after(100, update_revolver_ammo)
- 复选框回调控制启停
def toggle_battery_cheat(): global battery_active battery_active = battery_checkbox.get() if battery_active: update_battery() def toggle_revolver_cheat(): global revolver_active revolver_active = revolver_checkbox.get() if revolver_active: update_revolver_ammo()
- GUI部分和方案一一致
app = ctk.CTk() battery_checkbox = ctk.CTkCheckBox(app, text="无限电池", command=toggle_battery_cheat) battery_checkbox.pack(pady=5) revolver_checkbox = ctk.CTkCheckBox(app, text="无限左轮弹药", command=toggle_revolver_cheat) revolver_checkbox.pack(pady=5) app.mainloop()
关键细节
after()是tkinter(customtkinter基于它)的原生方法,任务会被加入GUI事件循环,不会阻塞界面响应- 取消勾选时只需把
battery_active设为False,下一次任务执行时就会停止递归 - 同样加异常捕获,避免游戏进程关闭时出错
额外提醒
- 务必使用静态基址+偏移获取内存地址,不要用动态地址,否则游戏重启后地址会失效
- 读写内存时注意匹配数据类型,比如如果是浮点型数值要用
write_float,别写错方法 - 线程方案中绝对不要在子线程里直接操作GUI控件,customtkinter的GUI操作必须在主线程(你这里只读写内存,没问题)
内容的提问来源于stack exchange,提问作者Zack27
相关产品推荐
相关产品推荐

