Skip to main content

Python bindings for OpenSpeedy game speed controller — accelerate or decelerate Windows games via DLL injection

Project description

OpenSpeedy · Python 游戏变速库

Python Platform License

OpenSpeedy 的 Python 绑定库 —— 将 OpenSpeedy 游戏变速器的核心加速功能封装为纯 Python 第三方库。通过向目标 Windows 进程注入 speedpatch DLL 并 Hook 时间相关 API,实现进程时间的加速与减速控制。

仅限 Windows 平台使用。


目录


安装

从 PyPI 安装(推荐)

pip install openspeedy

从源码安装

git clone https://github.com/game1024/OpenSpeedy.git
cd OpenSpeedy
pip install -e ".[dev]"

安装后会在包目录下包含预编译的 speedpatch64.dllspeedpatch32.dll


快速开始

from openspeedy import SpeedController

# 创建控制器(自动加载 speedpatch DLL)
sc = SpeedController()

# 枚举所有运行中的进程
for proc in sc.list_processes():
    if "game" in proc.name.lower():
        print(f"发现游戏进程: PID={proc.pid} 架构={proc.arch}")

# 注入 DLL 到目标进程
sc.inject(1234)

# 设置全局速度倍率(对所有已注入进程生效)
sc.set_speed(2.0)   # 2 倍速
sc.set_speed(0.5)   # 0.5 倍速(慢放)
sc.set_speed(1.0)   # 恢复正常速度

# 使用上下文管理器临时变速
with sc.speed_context(5.0):
    # 此代码块内以 5 倍速运行
    ...
# 退出后自动恢复之前的速度

# 查看状态
print(f"当前速度: {sc.get_speed()}x")
print(f"进程 1234 已启用: {sc.is_enabled(1234)}")

# 清理(弹出所有已注入的进程)
sc.close()

核心概念

全局速度因子

速度因子是一个 全局共享 的值,写入 DLL 的共享 PE 数据段后,所有已注入 speedpatch DLL 的进程都会立即感知变化。这意味着:

  • 调用 sc.set_speed(2.0) 一次,所有游戏进程同时加速
  • 不需要针对每个进程单独设置速度
  • 如果需要对不同进程使用不同速度,使用 enable(pid) / disable(pid) 控制每个进程的开关状态

注入 vs 启用

操作 含义
inject(pid) 将 speedpatch DLL 加载到目标进程中,并自动启用
eject(pid) 将 DLL 从目标进程中卸载
enable(pid) 对已注入的进程恢复变速效果
disable(pid) 对已注入的进程暂停变速效果(DLL 仍在进程中,但不修改时间)

快速枚举 vs 完整枚举

# 快速模式(默认):只返回 PID、名称、架构
procs = sc.list_processes(fast=True)

# 完整模式:额外获取窗口标题、内存、路径、管理员状态
procs = sc.list_processes(fast=False)

完整模式需要为每个进程调用 OpenProcess,速度较慢。建议先用快速模式筛选,再对关注的进程使用完整模式。


API 参考

SpeedController

方法 签名 说明
list_processes (fast: bool = True) -> list[ProcessInfo] 枚举所有运行中的 Windows 进程
inject (pid: int) -> None 注入 speedpatch DLL 到目标进程并启用
eject (pid: int) -> None 从目标进程卸载 speedpatch DLL
set_speed (factor: float) -> None 设置全局速度倍率(0.001 ~ 1000.0)
get_speed () -> float 获取当前全局速度倍率
enable (pid: int) -> None 启用指定进程的变速效果
disable (pid: int) -> None 暂停指定进程的变速效果
is_enabled (pid: int) -> bool 检查指定进程是否已启用变速
speed_context (factor: float) -> Iterator[None] 上下文管理器,临时变速后自动恢复
close () -> None 弹出所有由此控制器实例注入的进程

SpeedController 支持上下文管理器协议:

with SpeedController() as sc:
    sc.inject(pid)
    sc.set_speed(2.0)
# 退出时自动调用 close()

ProcessInfo

@dataclass
class ProcessInfo:
    pid: int              # 进程 ID
    name: str             # 可执行文件名(如 "notepad.exe")
    arch: str             # "x64" 或 "x86"
    window_title: str | None  # 主窗口标题,无可见窗口时为 None
    memory_kb: int            # 工作集大小(KB),快速模式下为 0
    exe_path: str | None      # 可执行文件完整路径
    is_admin: bool            # 是否以管理员权限运行

ModuleInfo

@dataclass
class ModuleInfo:
    name: str             # 模块文件名(如 "speedpatch64.dll")
    path: str             # 模块文件完整路径
    base_address: int     # 加载基址
    size: int             # 镜像大小(字节)

异常体系

所有异常继承自 OpenSpeedyError

OpenSpeedyError
├── PlatformNotSupportedError    # 非 Windows 平台
├── DLLNotFoundError             # speedpatch DLL 未找到
├── ProcessAccessDeniedError     # 无法打开进程(权限不足 / 受保护进程)
├── ProcessNotFoundError         # PID 不存在
├── ProcessArchitectureMismatch  # 跨架构注入(v1 限制)
├── InjectionError               # DLL 注入失败
├── EjectionError                # DLL 卸载失败
├── SpeedRangeError              # 速度因子超出范围
└── SpeedControlError            # DLL 操作运行时错误

每个异常都携带 Windows 错误码(e.win_error)和格式化消息:

from openspeedy import SpeedController, ProcessAccessDeniedError

sc = SpeedController()
try:
    sc.inject(4)  # System 进程 (PID 4),无法注入
except ProcessAccessDeniedError as e:
    print(f"访问被拒绝: {e}")
    print(f"Win32 错误码: {e.win_error}")

使用示例

示例 1:变速指定名称的进程

from openspeedy import SpeedController

def speed_up_game(game_name: str, factor: float):
    """查找并加速指定名称的游戏进程。"""
    sc = SpeedController()
    for proc in sc.list_processes(fast=True):
        if game_name.lower() in proc.name.lower():
            print(f"找到 {proc.name} (PID={proc.pid}, {proc.arch})")
            sc.inject(proc.pid)
    sc.set_speed(factor)
    print(f"已设置 {factor}x 速度")
    return sc  # 调用方负责调用 sc.close()

# 使用
ctrl = speed_up_game("game.exe", 2.0)
# ... 游戏运行中 ...
ctrl.close()

示例 2:监控进程启动并自动注入

import time
from openspeedy import SpeedController

def watch_and_inject(target_name: str, speed: float):
    """持续监控,发现目标进程后自动注入并变速。"""
    sc = SpeedController()
    sc.set_speed(speed)
    injected = set()

    try:
        while True:
            for proc in sc.list_processes(fast=True):
                if proc.name.lower() == target_name.lower():
                    if proc.pid not in injected:
                        try:
                            sc.inject(proc.pid)
                            injected.add(proc.pid)
                            print(f"已注入 {proc.name} (PID={proc.pid})")
                        except Exception as e:
                            print(f"注入失败 PID={proc.pid}: {e}")
            time.sleep(3)
    except KeyboardInterrupt:
        print("\n正在清理...")
        sc.close()

# 监控 notepad.exe,一旦启动就以 3 倍速运行
watch_and_inject("notepad.exe", 3.0)

示例 3:使用上下文管理器实现临时加速

from openspeedy import SpeedController

sc = SpeedController()
sc.inject(1234)

# 正常情况下 1 倍速
sc.set_speed(1.0)

def boss_fight():
    """Boss 战时临时加速到 3 倍。"""
    with sc.speed_context(3.0):
        # Boss 战逻辑...
        pass
    # 自动恢复 1 倍速

def grinding():
    """刷材料时 10 倍速。"""
    with sc.speed_context(10.0):
        # 刷材料逻辑...
        pass

示例 4:按进程分别控制开关

from openspeedy import SpeedController

sc = SpeedController()

# 注入两个游戏进程
sc.inject(1000)  # Game A
sc.inject(2000)  # Game B

sc.set_speed(5.0)  # 全局 5 倍速

# 暂停 Game B 的变速,Game A 保持 5 倍速
sc.disable(2000)

print(sc.is_enabled(1000))  # True
print(sc.is_enabled(2000))  # False

# 恢复 Game B
sc.enable(2000)

示例 5:获取进程详细信息

from openspeedy import SpeedController

sc = SpeedController()

# 完整枚举,获取所有信息
for proc in sc.list_processes(fast=False):
    if proc.window_title and proc.memory_kb > 100_000:
        print(f"[{proc.pid}] {proc.name}")
        print(f"  窗口: {proc.window_title}")
        print(f"  架构: {proc.arch}")
        print(f"  内存: {proc.memory_kb:,} KB")
        print(f"  路径: {proc.exe_path}")
        print(f"  管理员: {'是' if proc.is_admin else '否'}")
        print()

技术原理

架构概览

┌─────────────────────────────────────────┐
│  Python 进程                             │
│  ┌───────────────────────────────────┐  │
│  │  SpeedController                  │  │
│  │  ├─ list_processes()  ToolHelp   │  │
│  │  ├─ inject()          CreateRemoteThread
│  │  ├─ set_speed()       SP_SetSpeed │  │
│  │  └─ enable/disable    SP_Enable   │  │
│  └──────────────┬────────────────────┘  │
│                 │ ctypes                  │
│     ┌───────────▼───────────┐            │
│     │  speedpatch64.dll     │ (本地加载) │
│     │  - 共享数据段 (factor) │            │
│     │  - SP_* 导出函数       │            │
│     └───────────────────────┘            │
└─────────────────────────────────────────┘
         │ CreateRemoteThread
         │ + LoadLibraryW
         ▼
┌─────────────────────────────────────────┐
│  目标进程 (游戏)                         │
│  ┌───────────────────────────────────┐  │
│  │  speedpatch64.dll (MinHook)       │  │
│  │  ├─ Sleep              → ÷factor  │  │
│  │  ├─ GetTickCount       → ×factor  │  │
│  │  ├─ QueryPerformanceCounter       │  │
│  │  ├─ timeGetTime                   │  │
│  │  ├─ SetWaitableTimer              │  │
│  │  └─ ... (共 10 个时间 API)         │  │
│  └───────────────────────────────────┘  │
└─────────────────────────────────────────┘

Hook 的时间 API

函数 所属 DLL 变速策略
Sleep kernel32.dll 睡眠时间 ÷ 速度因子
SleepEx kernel32.dll 同上
SetTimer user32.dll 定时器间隔 ÷ 速度因子
SetWaitableTimer kernel32.dll 到期时间 ÷ 速度因子
SetWaitableTimerEx kernel32.dll 同上
timeSetEvent winmm.dll 延迟 ÷ 速度因子
timeGetTime winmm.dll 基线增量 × 速度因子
GetTickCount kernel32.dll 同上
GetTickCount64 kernel32.dll 同上
GetMessageTime user32.dll 同上
QueryPerformanceCounter kernel32.dll 同上
GetSystemTimeAsFileTime kernel32.dll 同上
GetSystemTimePreciseAsFileTime kernel32.dll 同上

两种变速策略:

  • 除法型(Sleep / SetTimer / SetWaitableTimer):将时间参数除以速度因子。例如 2 倍速时 Sleep(100) 实际只睡 50ms。
  • 增量缩放型(GetTickCount / QPC / timeGetTime):维护一个基线快照,每次调用时计算 baselineDetour + factor * (now - baselineKernel)。速度因子变化时自动重新基线,保证时间单调递增不会回退。

共享数据段

速度因子 factor 存储在 DLL 的共享 PE 数据段中:

#pragma data_seg("shared")
static std::atomic<double> factor = 1.0;
#pragma data_seg()
#pragma comment(linker, "/section:shared,RWS")

Windows 加载器将此段的同一物理内存页映射到每个加载该 DLL 的进程。任何进程写入后,所有进程立即可见。Python 端只需在本地加载 DLL 并调用 SP_SetSpeed() 即可全局生效。

按进程开关(命名文件映射)

每个注入进程在 DllMain 中创建 CreateFileMapping("OpenSpeedy.<PID>"),内含一个 bool 标志。Python 通过加载本地 DLL 调用 SP_Enable(pid) / SP_Disable(pid) 来操作该标志。当进程被禁用时,Hook 函数仍被调用,但 SpeedFactor() 返回 1.0(即不做任何修改)。


从源码构建

前提条件

构建步骤

# 克隆仓库
git clone https://github.com/game1024/OpenSpeedy.git
cd OpenSpeedy

# 构建 64 位 speedpatch DLL
cmake -S src-bridge/speedpatch -B build64 -A x64
cmake --build build64 --config Release

# 构建 32 位 speedpatch DLL
cmake -S src-bridge/speedpatch -B build32 -A Win32
cmake --build build32 --config Release

# 复制 DLL 到包数据目录
cp build64/Release/speedpatch64.dll openspeedy/data/
cp build32/Release/speedpatch32.dll openspeedy/data/

# 安装开发模式
pip install -e ".[dev]"

# 运行测试
pytest openspeedy/tests/ -v

要求与限制

系统要求

项目 要求
操作系统 Windows 10 或更高版本
Python 3.8 - 3.12
架构 x64 和 x86 均支持
权限 注入管理员进程需要以管理员身份运行 Python

v1 架构限制

同名架构注入:64 位 Python 解释器只能向 64 位目标进程注入;32 位 Python 只能向 32 位目标注入。这是因为 LoadLibraryW 在调用进程 kernel32.dll 中的地址必须与目标进程中的地址匹配。这与原始 OpenSpeedy 使用两个独立桥接进程的原因相同。如需向不同架构注入,请使用对应架构的 Python 解释器。

安全注意事项

  • 杀毒软件:DLL 注入行为可能被安全软件标记。请将 openspeedy/data/ 目录添加到白名单。
  • 反作弊系统:带有内核级反作弊的游戏(EAC、BattlEye、Vanguard、Ricochet 等)会检测并阻止此工具。在这些游戏中使用可能导致账号被封禁。
  • 在线竞技游戏:不建议在竞技类在线游戏中使用本工具。这违反大多数游戏的服务条款。
  • 仅供学习研究:本工具的设计目的是学习 Windows API Hook 和进程注入技术。

常见问题

Q: 注入失败,提示"访问被拒绝"?

以管理员身份运行 Python。某些进程(特别是系统服务和以管理员身份运行的程序)需要管理员权限才能打开。

Q: 变速后游戏崩溃?

过高的速度倍率(如 100x 以上)可能导致游戏物理引擎计算异常或除零错误。建议在 0.1x ~ 10x 范围内使用。

Q: 注入成功但没有加速效果?

确认:

  1. sc.is_enabled(pid) 返回 True
  2. sc.get_speed() 返回预期值
  3. 目标进程确实是 32 位游戏运行在 64 位系统上(检查 arch 字段)
Q: 如何在 macOS / Linux 上使用?

无法使用。此库依赖 Windows 特有的 API(CreateRemoteThreadLoadLibrary、共享 PE 数据段等),仅在 Windows 上可用。


许可证

  • openspeedy Python 库:GPL v3
  • 内置 speedpatch*.dll 包含 MinHook,使用 BSD 2-Clause 许可证

相关链接

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

openspeedy-0.1.1.tar.gz (86.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

openspeedy-0.1.1-py3-none-any.whl (83.2 kB view details)

Uploaded Python 3

File details

Details for the file openspeedy-0.1.1.tar.gz.

File metadata

  • Download URL: openspeedy-0.1.1.tar.gz
  • Upload date:
  • Size: 86.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for openspeedy-0.1.1.tar.gz
Algorithm Hash digest
SHA256 83838ed293c98d73f9b5f4ea891169a12d6e614b338cff1afd367f14cd02cecd
MD5 405d56c212fb5bf29d5ce0afbe933104
BLAKE2b-256 2f76dbba1d00de25ff5dfec6f49050e47bf172bae890f105dc02b36fd00f91a5

See more details on using hashes here.

File details

Details for the file openspeedy-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: openspeedy-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 83.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for openspeedy-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c64a1a09c75bc1847c8c79a89ea548dde98b3e042550ff2f024aa2556fafe904
MD5 d37277d9083ab9700c73ae130e653d98
BLAKE2b-256 634419b63d09ef7ec824548263caddc4a61fed09303376725d642b4fb885b039

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page