wszqkzqk/PvZ-Portable
GitHub: wszqkzqk/PvZ-Portable
一个基于社区研究从零重写的《植物大战僵尸:年度版》跨平台开源引擎,旨在通过现代跨平台技术将经典游戏体验移植到各类设备和操作系统上。
Stars: 545 | Forks: 87
# PvZ-Portable
[](https://deepwiki.com/wszqkzqk/PvZ-Portable)
一个**跨平台**、社区驱动的《植物大战僵尸:年度版》(Game of the Year Edition)重制项目,旨在将 100% 原汁原味的《植物大战僵尸》体验带到每一个平台。
| 🌿 原汁原味 | 🎮 跨平台移植 | 🛠️ 开源 |
| :---: | :---: | :---: |
| 几乎 100% 的玩法还原 | 支持 32/64 位系统
可在 Linux、Windows、macOS、Android、iOS、WebAssembly、Switch 等上运行 | OpenGL ES 2.0 & SDL | 🌐 **不想安装?** [直接在浏览器中体验吧!](https://wszqkzqk.github.io/pvz-portable-wasm/pvz-portable.html) (您仍需自备游戏数据文件。) **⚠️ 注意:** * 本仓库**不包含**任何由 PopCap Games 或 Electronic Arts 拥有的版权游戏资源(如图片、音乐或字体)。用户必须提供从**合法购买的**《植物大战僵尸:年度版》中获取的 `main.pak` 和 `properties/` 文件夹。 * 本代码库是基于社区研究(如[植物大战僵尸吧](https://tieba.baidu.com/f?ie=utf-8&kw=%E6%A4%8D%E7%89%A9%E5%A4%A7%E6%88%98%E5%83%B5%E5%B0%B8)、[PVZ Wiki](https://wiki.pvz1.com/doku.php?id=home) 和 [PvZ Tools](https://pvz.tools/memory/))手工重写的实现。代码编写时采用了如 SDL2 和 OpenGL ES 2.0(桌面端回退至 OpenGL 2.1)等跨平台后端。作者 (wszqkzqk) **从未对程序进行逆向工程**;作者完全是基于公开信息和游戏测试编写代码。此外,直接通过逆向工程生成的代码也**不会被接受**。 * 本项目仅出于**教育目的**,侧重于**跨平台移植技术**、引擎现代化,以及学习如何将经典游戏逻辑适配到各种硬件架构(例如,Nintendo Switch、3DS)。 * 非商业用途:本项目与 PopCap Games 或 Electronic Arts 没有任何关联、授权或认可。 * 项目图标和特定平台的标志由我 (wszqkzqk) 在 AI 图像生成工具的帮助下制作,并非 PopCap/EA 的官方资产。 * 使用本项目游玩游戏,您**必须**通过在 [EA 官方网站](https://www.ea.com/games/plants-vs-zombies/plants-vs-zombies) 或 [Steam](https://store.steampowered.com/app/3590/Plants_vs_Zombies_GOTY_Edition/) 购买来获取原始游戏文件。 ## 功能 - [x] 使用 SDL + OpenGL ES 2.0 进行渲染(桌面端回退至 OpenGL 2.1) - 同时支持**调整窗口大小**,这在原版游戏中是无法实现的 - **为什么选择 OpenGL ES 2.0?** GLES 2.0 几乎是所有现代 GPU API 的公共子集——每个桌面端 OpenGL 2.1+ 驱动、移动 GPU 和游戏主机都原生支持它。这意味着游戏可以**开箱即用**地在各处运行,无需额外依赖。如果需要,还可以选择性地使用 [ANGLE](https://chromium.googlesource.com/angle/angle) 将调用转换为 DirectX/Metal/Vulkan。 - [x] 实现基于 [SDL Mixer X](https://github.com/WohlSoft/SDL-Mixer-X) 的跨平台音频系统 - 本项目使用了 SDL Mixer X 的一个分支,该分支通过使用 libopenmpt 增加了对 MO3 格式的兼容性。此分支位于 SexyAppFramework/sound/SDL-Mixer-X 下 - [x] 通过禁用缓存,为 RAM 极其有限的主机平台节省更多内存 - [x] **兼容**原版 PvZ 年度版的***全局用户数据***(个人信息、冒险模式进度、金币、禅境花园等,存储在 `user*.dat` 中) - [x] 在保持兼容性的同时修复了 2038 年问题 - [x] **跨平台的中途存档**格式 `.v4` 支持(可在 Windows、Linux、macOS、Android、Switch 等之间共享**中途存档**) - [x] 支持将 `.v4` 存档文件导出/导入为人类可读的 YAML 格式,以便于编辑 - [x] 使用 `std::thread` 实现跨平台线程支持 - [x] 使用 `std::filesystem` 实现跨平台文件系统支持 - [x] 程序内部统一使用 UTF-8 编码 - [x] **多语言支持**:支持各种语言版本的官方年度版游戏资源数据,包括**中文、德语、西班牙语、法语和意大利语**。 - [x] 32 位和 64 位构建支持 - [x] 不同的 CPU 架构支持(i686、x86_64、aarch64、riscv64、loongarch64 等) - [x] 在所有平台上支持 Unicode 路径 - [x] 支持不同的字节序(小端序和大端序) - [x] 跨字节序的存档数据兼容性 - 理论上支持大端序平台,但由于缺乏硬件而未经测试 - [x] 解锁原版游戏中包含额外关卡的**隐藏极限模式页面** - 要解锁它,请打开 迷你游戏 / 益智 / 生存 模式的选择界面,并在任意空白区域**连续快速点击 5 次** 本项目支持以下平台(包括但不限于): | 平台 | 数据路径 | 状态 | |-----------------|------------------------------|----------------------------------------------------------------------------------------| | Linux | 可执行文件目录(资源);用户专属的应用程序数据目录用于可写文件 | 可运行 | | Windows | 可执行文件目录(资源);用户专属的应用程序数据目录用于可写文件 | 可运行 | | macOS | 可执行文件目录(资源);用户专属的应用程序数据目录用于可写文件 | 可运行 | | BSD 家族 | 可执行文件目录(资源);用户专属的应用程序数据目录用于可写文件 | 可运行(至少在 FreeBSD 上已验证) | | Haiku | 可执行文件目录(资源);用户专属的应用程序数据目录用于可写文件 | 部分可运行:无音乐 | | Android | `Android/data/io.github.wszqkzqk.pvzportable/files/` | 可运行 | | iOS / iPadOS | 应用程序 Documents 目录(“文件”应用) | 可运行(仅限侧载;未签名 IPA) | | Web (WASM) | 浏览器 IndexedDB(存档);资源在运行时上传 | 可运行(需要 HTTP 服务器) | | Nintendo Switch | sdmc:/switch/PvZPortable | 可在真机上运行。Kenji-NX 在启动时崩溃。 | | Nintendo 3DS | sdmc:/3ds/PvZPortable | Old 3DS 可能内存不足,New 3DS 上勉强可运行(已停止维护) | 要运行游戏,您需要 PvZ 年度版的游戏数据。请将 `main.pak` 和 `properties/` 文件夹放在 `pvz-portable` 可执行文件旁边(游戏会相对于可执行文件所在的目录查找资源)。如果您愿意,也可以使用解压后的数据来代替 `main.pak`。 关于可写数据和缓存的说明: - 默认情况下,游戏会从可执行文件所在目录读取资源(如 `main.pak` 和 `properties/`),因此您可以从任何工作目录启动二进制文件,它依然能找到这些资源。 - 各用户的可写文件(设置、存档、编译缓存、截图)存储在**操作系统推荐的应用程序数据路径**中。在当前的构建版本中,这些文件位于 `io.github.wszqkzqk/PvZPortable` 下,包含以下子文件夹: - `userdata/` — 玩家存档文件。 - 如果您使用 64 位版本,则是 `cache64/`;如果您使用 32 位版本,则是 `cache32/` — 编译后的二进制缓存(动画重放 / 编译后的定义)。这些缓存是**本地启动**生成的工件(**原生布局**),不是跨平台文件;当缓存/schema检查失败时,游戏会透明地从源数据重新编译。 - `registry.regemu` — 设置/注册表模拟。 示例: - Linux: `~/.local/share/io.github.wszqkzqk/PvZPortable/` - Windows: `%APPDATA%\io.github.wszqkzqk\PvZPortable\` - macOS: `~/Library/Application Support/io.github.wszqkzqk/PvZPortable/` 您可以通过命令行参数自定义这些路径: - `-resdir="<路径>"`:设置**资源目录**(即 `main.pak` 和 `properties/` 所在的位置)。这仅影响游戏查找资源的位置,不影响其保存数据的位置。 - `-savedir="<路径>"`:设置**存档数据目录**(即设置、存档、缓存和截图的存储位置)。这将覆盖操作系统默认推荐的应用程序数据路径。 **注意:** 您**必须**使用 `-param="<您的路径>"` 格式。**不支持**使用空格分隔的值(例如 `-resdir 路径`)。 ### Android 特别说明 从 [Releases](https://github.com/wszqkzqk/PvZ-Portable/releases) 页面下载 APK 或自行构建。由于本项目**不包含**任何游戏资源,您需要从**合法购买的**《植物大战僵尸:年度版》中**导入游戏资源**。 #### 首次启动 1. **安装 APK**(您可能需要启用“安装来自未知来源的应用”)。 2. **启动应用程序** — 由于未找到游戏资源,将自动出现**资源导入界面**。 3. 通过选择以下任一方式**导入游戏资源**: - 一个包含 `main.pak` 和 `properties/` 的 **ZIP 文件**(可以在 ZIP 的根目录下,也可以在其中一个包装目录内,例如 `PvZ/main.pak`)。 - 一个直接包含 `main.pak` 和 `properties/` 的**文件夹**,或者其直接子文件夹包含这些文件。 4. 导入成功后按**开始游戏**。 #### 之后管理数据 在桌面上的应用程序图标上长按以访问**管理数据**快捷方式,这将打开资源管理界面,您可以在此重新导入资源、导出存档或导入存档。 #### 注意事项 - 需要 Android 9.0+。预编译的 APK 仅包含 arm64-v8a 架构,但如有需要,**您可以为其他架构进行构建**。 - 所有数据都存储在 `Android/data/io.github.wszqkzqk.pvzportable/files/` 中。不需要额外的存储权限 — 应用程序使用 **存储访问框架 (SAF)** 进行所有导入和导出。 - 存档数据与桌面版互通。详情请参阅[存档数据部分](#save-data-compatibility-user-data-and-mid-level-saves)章节。 - Android 移植版是本项目**跨平台移植研究**的一部分。它保留了原版游戏 4:3 的宽高比和基于鼠标的输入模型 — **未进行任何针对触摸屏的 UI 优化**。SDL2 会自动将触摸事件映射为鼠标输入,因此游戏可以运行,但并不是为移动端人体工学设计的。 ### iOS / iPadOS 特别说明 从 [Releases](https://github.com/wszqkzqk/PvZ-Portable/releases) 页面下载未签名的 IPA,或使用 `ios/build-ios.sh` 自行构建。此 IPA 必须进行侧载 — 常见的方法包括 [AltStore](https://altstore.io/)、[TrollStore](https://github.com/opa334/TrollStore),或使用免费的 Apple ID 直接从 Xcode 部署。 #### 导入游戏资源 应用程序的 Documents 文件夹可通过 iTunes/Finder 文件共享和 iOS 的“文件”应用(`UIFileSharingEnabled`)访问。将 `main.pak` 和 `properties/` 文件夹直接放入该 App 的 Documents 目录中(在“文件”应用中显示为“PvZ Portable”)。 #### 注意事项 - 需要 iOS 15.0+(arm64)。 - 免费 Apple ID 签名将在 7 天后过期;通过 TrollStore 安装则是永久的。 - 与 Android 移植版具有相同的触摸到鼠标的映射和宽高比行为。 ### 在浏览器中游玩 (WebAssembly) **[▶ 在线游玩](https://wszqkzqk.github.io/pvz-portable-wasm/pvz-portable.html)** — 打开链接,从您合法购买的游戏资源中加载它们,可以选择通过 ZIP 压缩包,或者提供 `main.pak` 加上 `properties/` 文件夹,然后点击**开始游戏**。所有文件都将保留在您本地的浏览器中,**绝不会被上传到任何服务器**(托管该网站的站点完全是静态的)。存档数据存储在您浏览器的 IndexedDB 中,可以通过屏幕上的按钮从 ZIP 或文件夹导入,或导出为 ZIP。 您也可以[下载 WASM 构建版本](https://github.com/wszqkzqk/PvZ-Portable/releases)并自行托管。请注意,HTML 文件必须通过 HTTP 服务(例如 `python3 -m http.server`)提供 — 由于浏览器的安全限制,直接作为本地文件打开是无法运行的。 ## 游戏版本兼容性 本项目是针对《植物大战僵尸》**年度版 .2.0.1073** EN(PopCap 独立发行版)进行设计和测试的。**非英语年度版**(基于 1.2.0.1073 的 1.2.0.1093 DE/ES/FR/IT 或 1.1.0.1056 ZH)以及 **Steam 年度版 1.2.0.1096** 也可以完全运行 — 所有游戏机制都能正常工作。唯一的区别在于各版本间字符串键名更改导致的轻微外观 UI 文本问题,用户可以通过自定义 `properties/default.xml` **轻松修复**这些问题(见下文)。 **建议:** 使用 **1.2.0.1073 EN** 资源包以获得最佳的**开箱即用**体验。
### 多语言支持
PvZ-Portable 支持《植物大战僵尸》**年度版**的**非英语版本**游戏资源数据。引擎能够处理带有 BOM 编码的文本文件,并将传统的 Windows-1252 编码转换为 UTF-8,因此本地化的文件将被正确加载。如果游戏数据中存在 `properties/default.xml` 和/或 `properties/Layout.xml`,它们会在 `LawnStrings.txt` **之后**被加载,并可以覆盖任何字符串值。这两个文件都是可选的;如果缺失,则使用内置的英语默认值。
由于 `default.xml` 的优先级高于 `LawnStrings.txt`,用户还可以**创建或编辑自己的 `properties/default.xml`** 来添加或覆盖任何字符串键,这使得无需修改引擎即可轻松修复特定版本的显示问题。
## 依赖
在 PC 上构建之前,请确保已安装必要的依赖项:
- **构建工具**:`CMake`、`Ninja`、支持 **C++20** 的 C/C++ 编译器(如 `gcc`、`clang`、`MSVC`)(还需要支持 C++20 的标准库实现,如 `libstdc++`、`libc++` 或 MSVC STL)
- **图形**:`OpenGL ES 2.0` 或 `OpenGL 2.1+`(在运行时通过 SDL2 自动检测)
- **音频**:`libopenmpt`、`libogg`、`libvorbis`、`mpg123`
- **图像**:`libpng`、`libjpeg-turbo`
- **窗口/输入**:`SDL2`
### Arch Linux
您可以使用以下命令安装所需的依赖项:
```
sudo pacman -S --needed base-devel cmake libjpeg-turbo libogg libopenmpt libpng libvorbis mpg123 ninja sdl2-compat
```
### Debian/Ubuntu
您可以使用以下命令安装所需的依赖项:
```
sudo apt install cmake ninja-build libogg-dev libjpeg-dev libopenmpt-dev libpng-dev libvorbis-dev libmpg123-dev libsdl2-dev
```
### Windows (MSYS2 UCRT64)
您可以使用以下命令安装所需的依赖项:
```
pacman -S --needed base-devel mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-libjpeg-turbo mingw-w64-ucrt-x86_64-libopenmpt mingw-w64-ucrt-x86_64-libogg mingw-w64-ucrt-x86_64-libpng mingw-w64-ucrt-x86_64-libvorbis mingw-w64-ucrt-x86_64-mpg123 mingw-w64-ucrt-x86_64-ninja mingw-w64-ucrt-x86_64-SDL2
```
### macOS (Homebrew)
您可以使用 [Homebrew](https://brew.sh/) 并通过以下命令安装所需的依赖项:
```
brew install cmake dylibbundler jpeg-turbo libogg libopenmpt libpng libvorbis mpg123 ninja sdl2
```
## 构建说明
在 `CMakeLists.txt` 文件所在的目录运行以下命令(假设您已经安装了 CMake 和其他依赖项):
```
cmake -G Ninja -B build
```
```
cmake --build build
```
### 性能优化
建议使用 **Release** 构建类型以获得最佳性能,因为它通常意味着编译器优化:
```
cmake -G Ninja -B build -DCMAKE_BUILD_TYPE=Release
```
对于高级用户,您还可以指定 `CFLAGS` 和 `CXXFLAGS` 来启用特定于架构的优化(例如 `-march=native` 以充分利用您 CPU 的指令集):
```
cmake -G Ninja -B build -DCMAKE_C_FLAGS="-march=native" -DCMAKE_CXX_FLAGS="-march=native" -DCMAKE_BUILD_TYPE=Release
```
### 配置选项
您可以通过在第一条 `cmake` 命令中添加选项来自定义游戏功能:
| 选项 | 默认值 | 描述 |
| :--- | :--- | :--- |
| `PVZ_DEBUG` | `OFF`
(如果 `CMAKE_BUILD_TYPE` 是 `Debug` 则为 `ON`) | 启用**作弊键**、调试显示及其他调试功能。 | | `DO_FIX_BUGS` | `OFF` | 应用社区修复程序,修复官方 1.2.0.1073 GOTY 版本的“Bug”。[^1] 然而,这些“Bug”通常被许多玩家**视为“特性”**。 | | `CONSOLE` | `OFF`
(如果 `CMAKE_BUILD_TYPE` 是 `Debug` 则为 `ON`) | 显示控制台窗口(仅限 Windows)。 | | `BUILD_STATIC` | `OFF` | 静态链接以创建独立可执行文件(仅限带有基于 MinGW 工具链的 Windows)。对于 MSVC,请使用 vcpkg 的 `-static` triplet。 | [^1]: 当前的 `DO_FIX_BUGS` 包含以下修复: - 修复了“我是僵尸”模式中蹦极僵尸重复掉落阳光/物品的问题。 - 使被精神控制的巨人僵尸砸击敌方僵尸而不是植物。 - 使被精神控制的巨人僵尸投掷出被精神控制的小鬼僵尸(包含缩放比例、生命值和方向的修正)。 - 使被精神控制的巨人僵尸能在恐怖陶罐模式中砸碎陶罐。 - 使被精神控制的豌豆/机枪头僵尸向前方射击而不是向后。 - 使被精神控制的火爆辣椒/倭瓜僵尸伤害敌方僵尸而不是植物。 - 修正了被精神控制的倭瓜僵尸在跟踪和砸击敌方僵尸时的协调问题。 - 使被精神控制的火爆辣椒僵尸能正确清除僵王博士的技能(冰球/火球)和梯子逻辑。 - 同步了舞者僵尸的动画(修复了“女仆”位移 Bug)。 - 修复了梯子僵尸手臂恢复时的视觉故障。 - 修复了 6 行道(泳池)关卡中僵王博士的攻击(休旅车、火球/冰球)和召唤范围覆盖问题。 示例:在 **Release 构建** 中手动启用 `PVZ_DEBUG`,以便您在拥有优化性能的同时使用**作弊键**: ``` cmake -G Ninja -B build -DCMAKE_BUILD_TYPE=Release -DPVZ_DEBUG=ON ``` 如果运行这些命令未能成功构建,请创建一个 Issue 并详细说明您的问题。 ## 存档数据兼容性(用户数据和中途存档) PvZ-Portable 使用两种不同类型的存档数据: 1. **全局用户数据** (`users.dat`, `user1.dat` 等): * 存储个人资料信息、冒险模式进度、金币、禅境花园等。 * 与原版 PC 游戏格式**完全兼容**。 * 依靠设计本身已经实现了跨平台(使用显式序列化)。 2. **中途存档状态** (`game1_0.v4` 等,旧版的 `game1_0.dat` 等): * 存储使用“保存并退出”时的关卡确切状态(僵尸、子弹、植物等)。 * 游戏现在默认**仅**写入 `*.v4` 文件: * `*.v4` 文件:**跨平台格式**。完全**支持**分享这些文件以在不同的平台之间转移进度。 * `*.dat` 文件:旧版本中的**传统转储**。包含原始内存转储。**请勿**跨平台分享此文件,因为由于架构差异它会导致崩溃。 * 加载时,游戏**首选** `.v4`;`*.dat` 仅作为迁移兼容性的回退。 * 如果从旧版的 `*.dat` 加载存档,游戏会自动将其重新保存为 `*.v4`,并在成功迁移后删除旧版的 `*.dat`。 ### 为什么要有新的中途存档格式? 原版游戏的中途存档格式 (`.dat`) 实际上是将原始内存结构直接转储到磁盘上。这种方式速度快但很脆弱,因为它依赖于特定的内存布局,这在以下情况中会失效: * **不同的 CPU 架构**:x86、ARM、RISC-V、LoongArch(内存对齐方式不同)。 * **32 位与 64 位构建版本**:指针大小和结构体布局不同。 * **不同的编译器**:MSVC 对比 GCC/Clang(内存填充、枚举大小、结构体封装不同)。 因此,传统存档通常无法保证在这些变体之间互通加载。为了解决这个问题,**格式 v4** 使用 Type-Length-Value (TLV) 标签逐字段序列化游戏对象。这确保了在 x86_64 Linux 机器上保存的关卡可以在 LoongArch 或 ARM (Switch) 机器上加载而不会崩溃。 ### 格式 v4 的开发者指南 - 将新字段添加为新的 TLV ID;不要重用 ID。 - 加载旧存档时,对缺失的字段保留默认值。 - 避免对可能更改布局的数据进行原始结构体转储;首选使用固定宽度的基本类型进行显式的逐字段同步。 ### 存档编辑和转换工具 这里有一个 Python 脚本 `scripts/pvzp-v4-converter.py` 可用于检查和修改 `.v4` 存档文件。 **功能:** * **信息**:查看基本的存档统计数据(波数、阳光、僵尸等)。 * **导出为 YAML**:将二进制 `.v4` 文件转换为人类可读的 YAML 格式,以查看/编辑与游戏玩法相关的数据。 * **从 YAML 导入**:将修改后的 YAML 转换回 `.v4` 格式,并生成正确的校验和。 **用法:** ``` # 根据需要修改这些路径 # 查看基本信息 python scripts/pvzp-v4-converter.py info ~/.local/io.github.wszqkzqk/PvZPortable/userdata/game1_13.v4 # 导出为 YAML 以进行编辑 python scripts/pvzp-v4-converter.py export ~/.local/io.github.wszqkzqk/PvZPortable/userdata/game1_13.v4 level.yaml # 导入回存档 # **备份**你的原始 .v4 文件! mv ~/.local/io.github.wszqkzqk/PvZPortable/userdata/game1_13.v4 ~/.local/io.github.wszqkzqk/PvZPortable/userdata/game1_13.v4.bak python scripts/pvzp-v4-converter.py import level.yaml ~/.local/io.github.wszqkzqk/PvZPortable/userdata/game1_13.v4 ``` ## 许可证 **版权所有 (C) 2026 Zhou Qiankang**
本项目根据 [**GNU 宽通用公共许可证 v3.0**](https://www.gnu.org/licenses/lgpl-3.0.html) 或更高版本 (LGPL-3.0-or-later) 的条款进行授权。
* 仓库根目录包含了完整的许可证文本:
* `LICENSE` — LGPL-3.0 文本
* `COPYING` — GPL-3.0 文本,由 LGPL-3.0 引用
* 本代码按“原样”提供,**不提供任何形式的**担保**。
* **原始游戏 IP(植物大战僵尸)归 PopCap/EA 所有**。此许可证**仅适用于**本仓库中的代码实现。
* 本项目**不包含**来自原版游戏的任何受版权保护的资源。
### PopCap Games Framework 致谢
`SexyAppFramework` 目录可能包含最初基于 **PopCap Games Framework** 的代码。此代码受其宽松的 **[PopCap Games Framework 许可证](src/SexyAppFramework/LICENSE)** 约束。在保留原始代码的范围内,适用以下致谢:
请注意,随着时间的推移,这些代码已经在社区的努力下,在 **LGPL-3.0-or-later** 许可证下经过了**深度重构**、**优化**和**现代化**。
## 致谢
- **PopCap Games**:感谢他们创造了这款了不起的游戏,并以宽松的许可证向公众发布了他们的框架。
- **SDL 团队**:感谢他们提供了为本移植版提供动力的惊人跨平台开发库。
- **OpenMPT 团队**:感谢他们提供了 libopenmpt,实现了高质量的 MO3 音乐播放。
- 感谢所有曾经或正在积极参与这个惊人项目的贡献者,特别是 [@Headshotnoby](https://www.github.com/headshot2017) 和 [@Patoke](https://www.github.com/Patoke),感谢他们奠定的基础工作。
可在 Linux、Windows、macOS、Android、iOS、WebAssembly、Switch 等上运行 | OpenGL ES 2.0 & SDL | 🌐 **不想安装?** [直接在浏览器中体验吧!](https://wszqkzqk.github.io/pvz-portable-wasm/pvz-portable.html) (您仍需自备游戏数据文件。) **⚠️ 注意:** * 本仓库**不包含**任何由 PopCap Games 或 Electronic Arts 拥有的版权游戏资源(如图片、音乐或字体)。用户必须提供从**合法购买的**《植物大战僵尸:年度版》中获取的 `main.pak` 和 `properties/` 文件夹。 * 本代码库是基于社区研究(如[植物大战僵尸吧](https://tieba.baidu.com/f?ie=utf-8&kw=%E6%A4%8D%E7%89%A9%E5%A4%A7%E6%88%98%E5%83%B5%E5%B0%B8)、[PVZ Wiki](https://wiki.pvz1.com/doku.php?id=home) 和 [PvZ Tools](https://pvz.tools/memory/))手工重写的实现。代码编写时采用了如 SDL2 和 OpenGL ES 2.0(桌面端回退至 OpenGL 2.1)等跨平台后端。作者 (wszqkzqk) **从未对程序进行逆向工程**;作者完全是基于公开信息和游戏测试编写代码。此外,直接通过逆向工程生成的代码也**不会被接受**。 * 本项目仅出于**教育目的**,侧重于**跨平台移植技术**、引擎现代化,以及学习如何将经典游戏逻辑适配到各种硬件架构(例如,Nintendo Switch、3DS)。 * 非商业用途:本项目与 PopCap Games 或 Electronic Arts 没有任何关联、授权或认可。 * 项目图标和特定平台的标志由我 (wszqkzqk) 在 AI 图像生成工具的帮助下制作,并非 PopCap/EA 的官方资产。 * 使用本项目游玩游戏,您**必须**通过在 [EA 官方网站](https://www.ea.com/games/plants-vs-zombies/plants-vs-zombies) 或 [Steam](https://store.steampowered.com/app/3590/Plants_vs_Zombies_GOTY_Edition/) 购买来获取原始游戏文件。 ## 功能 - [x] 使用 SDL + OpenGL ES 2.0 进行渲染(桌面端回退至 OpenGL 2.1) - 同时支持**调整窗口大小**,这在原版游戏中是无法实现的 - **为什么选择 OpenGL ES 2.0?** GLES 2.0 几乎是所有现代 GPU API 的公共子集——每个桌面端 OpenGL 2.1+ 驱动、移动 GPU 和游戏主机都原生支持它。这意味着游戏可以**开箱即用**地在各处运行,无需额外依赖。如果需要,还可以选择性地使用 [ANGLE](https://chromium.googlesource.com/angle/angle) 将调用转换为 DirectX/Metal/Vulkan。 - [x] 实现基于 [SDL Mixer X](https://github.com/WohlSoft/SDL-Mixer-X) 的跨平台音频系统 - 本项目使用了 SDL Mixer X 的一个分支,该分支通过使用 libopenmpt 增加了对 MO3 格式的兼容性。此分支位于 SexyAppFramework/sound/SDL-Mixer-X 下 - [x] 通过禁用缓存,为 RAM 极其有限的主机平台节省更多内存 - [x] **兼容**原版 PvZ 年度版的***全局用户数据***(个人信息、冒险模式进度、金币、禅境花园等,存储在 `user*.dat` 中) - [x] 在保持兼容性的同时修复了 2038 年问题 - [x] **跨平台的中途存档**格式 `.v4` 支持(可在 Windows、Linux、macOS、Android、Switch 等之间共享**中途存档**) - [x] 支持将 `.v4` 存档文件导出/导入为人类可读的 YAML 格式,以便于编辑 - [x] 使用 `std::thread` 实现跨平台线程支持 - [x] 使用 `std::filesystem` 实现跨平台文件系统支持 - [x] 程序内部统一使用 UTF-8 编码 - [x] **多语言支持**:支持各种语言版本的官方年度版游戏资源数据,包括**中文、德语、西班牙语、法语和意大利语**。 - [x] 32 位和 64 位构建支持 - [x] 不同的 CPU 架构支持(i686、x86_64、aarch64、riscv64、loongarch64 等) - [x] 在所有平台上支持 Unicode 路径 - [x] 支持不同的字节序(小端序和大端序) - [x] 跨字节序的存档数据兼容性 - 理论上支持大端序平台,但由于缺乏硬件而未经测试 - [x] 解锁原版游戏中包含额外关卡的**隐藏极限模式页面** - 要解锁它,请打开 迷你游戏 / 益智 / 生存 模式的选择界面,并在任意空白区域**连续快速点击 5 次** 本项目支持以下平台(包括但不限于): | 平台 | 数据路径 | 状态 | |-----------------|------------------------------|----------------------------------------------------------------------------------------| | Linux | 可执行文件目录(资源);用户专属的应用程序数据目录用于可写文件 | 可运行 | | Windows | 可执行文件目录(资源);用户专属的应用程序数据目录用于可写文件 | 可运行 | | macOS | 可执行文件目录(资源);用户专属的应用程序数据目录用于可写文件 | 可运行 | | BSD 家族 | 可执行文件目录(资源);用户专属的应用程序数据目录用于可写文件 | 可运行(至少在 FreeBSD 上已验证) | | Haiku | 可执行文件目录(资源);用户专属的应用程序数据目录用于可写文件 | 部分可运行:无音乐 | | Android | `Android/data/io.github.wszqkzqk.pvzportable/files/` | 可运行 | | iOS / iPadOS | 应用程序 Documents 目录(“文件”应用) | 可运行(仅限侧载;未签名 IPA) | | Web (WASM) | 浏览器 IndexedDB(存档);资源在运行时上传 | 可运行(需要 HTTP 服务器) | | Nintendo Switch | sdmc:/switch/PvZPortable | 可在真机上运行。Kenji-NX 在启动时崩溃。 | | Nintendo 3DS | sdmc:/3ds/PvZPortable | Old 3DS 可能内存不足,New 3DS 上勉强可运行(已停止维护) | 要运行游戏,您需要 PvZ 年度版的游戏数据。请将 `main.pak` 和 `properties/` 文件夹放在 `pvz-portable` 可执行文件旁边(游戏会相对于可执行文件所在的目录查找资源)。如果您愿意,也可以使用解压后的数据来代替 `main.pak`。 关于可写数据和缓存的说明: - 默认情况下,游戏会从可执行文件所在目录读取资源(如 `main.pak` 和 `properties/`),因此您可以从任何工作目录启动二进制文件,它依然能找到这些资源。 - 各用户的可写文件(设置、存档、编译缓存、截图)存储在**操作系统推荐的应用程序数据路径**中。在当前的构建版本中,这些文件位于 `io.github.wszqkzqk/PvZPortable` 下,包含以下子文件夹: - `userdata/` — 玩家存档文件。 - 如果您使用 64 位版本,则是 `cache64/`;如果您使用 32 位版本,则是 `cache32/` — 编译后的二进制缓存(动画重放 / 编译后的定义)。这些缓存是**本地启动**生成的工件(**原生布局**),不是跨平台文件;当缓存/schema检查失败时,游戏会透明地从源数据重新编译。 - `registry.regemu` — 设置/注册表模拟。 示例: - Linux: `~/.local/share/io.github.wszqkzqk/PvZPortable/` - Windows: `%APPDATA%\io.github.wszqkzqk\PvZPortable\` - macOS: `~/Library/Application Support/io.github.wszqkzqk/PvZPortable/` 您可以通过命令行参数自定义这些路径: - `-resdir="<路径>"`:设置**资源目录**(即 `main.pak` 和 `properties/` 所在的位置)。这仅影响游戏查找资源的位置,不影响其保存数据的位置。 - `-savedir="<路径>"`:设置**存档数据目录**(即设置、存档、缓存和截图的存储位置)。这将覆盖操作系统默认推荐的应用程序数据路径。 **注意:** 您**必须**使用 `-param="<您的路径>"` 格式。**不支持**使用空格分隔的值(例如 `-resdir 路径`)。 ### Android 特别说明 从 [Releases](https://github.com/wszqkzqk/PvZ-Portable/releases) 页面下载 APK 或自行构建。由于本项目**不包含**任何游戏资源,您需要从**合法购买的**《植物大战僵尸:年度版》中**导入游戏资源**。 #### 首次启动 1. **安装 APK**(您可能需要启用“安装来自未知来源的应用”)。 2. **启动应用程序** — 由于未找到游戏资源,将自动出现**资源导入界面**。 3. 通过选择以下任一方式**导入游戏资源**: - 一个包含 `main.pak` 和 `properties/` 的 **ZIP 文件**(可以在 ZIP 的根目录下,也可以在其中一个包装目录内,例如 `PvZ/main.pak`)。 - 一个直接包含 `main.pak` 和 `properties/` 的**文件夹**,或者其直接子文件夹包含这些文件。 4. 导入成功后按**开始游戏**。 #### 之后管理数据 在桌面上的应用程序图标上长按以访问**管理数据**快捷方式,这将打开资源管理界面,您可以在此重新导入资源、导出存档或导入存档。 #### 注意事项 - 需要 Android 9.0+。预编译的 APK 仅包含 arm64-v8a 架构,但如有需要,**您可以为其他架构进行构建**。 - 所有数据都存储在 `Android/data/io.github.wszqkzqk.pvzportable/files/` 中。不需要额外的存储权限 — 应用程序使用 **存储访问框架 (SAF)** 进行所有导入和导出。 - 存档数据与桌面版互通。详情请参阅[存档数据部分](#save-data-compatibility-user-data-and-mid-level-saves)章节。 - Android 移植版是本项目**跨平台移植研究**的一部分。它保留了原版游戏 4:3 的宽高比和基于鼠标的输入模型 — **未进行任何针对触摸屏的 UI 优化**。SDL2 会自动将触摸事件映射为鼠标输入,因此游戏可以运行,但并不是为移动端人体工学设计的。 ### iOS / iPadOS 特别说明 从 [Releases](https://github.com/wszqkzqk/PvZ-Portable/releases) 页面下载未签名的 IPA,或使用 `ios/build-ios.sh` 自行构建。此 IPA 必须进行侧载 — 常见的方法包括 [AltStore](https://altstore.io/)、[TrollStore](https://github.com/opa334/TrollStore),或使用免费的 Apple ID 直接从 Xcode 部署。 #### 导入游戏资源 应用程序的 Documents 文件夹可通过 iTunes/Finder 文件共享和 iOS 的“文件”应用(`UIFileSharingEnabled`)访问。将 `main.pak` 和 `properties/` 文件夹直接放入该 App 的 Documents 目录中(在“文件”应用中显示为“PvZ Portable”)。 #### 注意事项 - 需要 iOS 15.0+(arm64)。 - 免费 Apple ID 签名将在 7 天后过期;通过 TrollStore 安装则是永久的。 - 与 Android 移植版具有相同的触摸到鼠标的映射和宽高比行为。 ### 在浏览器中游玩 (WebAssembly) **[▶ 在线游玩](https://wszqkzqk.github.io/pvz-portable-wasm/pvz-portable.html)** — 打开链接,从您合法购买的游戏资源中加载它们,可以选择通过 ZIP 压缩包,或者提供 `main.pak` 加上 `properties/` 文件夹,然后点击**开始游戏**。所有文件都将保留在您本地的浏览器中,**绝不会被上传到任何服务器**(托管该网站的站点完全是静态的)。存档数据存储在您浏览器的 IndexedDB 中,可以通过屏幕上的按钮从 ZIP 或文件夹导入,或导出为 ZIP。 您也可以[下载 WASM 构建版本](https://github.com/wszqkzqk/PvZ-Portable/releases)并自行托管。请注意,HTML 文件必须通过 HTTP 服务(例如 `python3 -m http.server`)提供 — 由于浏览器的安全限制,直接作为本地文件打开是无法运行的。 ## 游戏版本兼容性 本项目是针对《植物大战僵尸》**年度版 .2.0.1073** EN(PopCap 独立发行版)进行设计和测试的。**非英语年度版**(基于 1.2.0.1073 的 1.2.0.1093 DE/ES/FR/IT 或 1.1.0.1056 ZH)以及 **Steam 年度版 1.2.0.1096** 也可以完全运行 — 所有游戏机制都能正常工作。唯一的区别在于各版本间字符串键名更改导致的轻微外观 UI 文本问题,用户可以通过自定义 `properties/default.xml` **轻松修复**这些问题(见下文)。 **建议:** 使用 **1.2.0.1073 EN** 资源包以获得最佳的**开箱即用**体验。
使用非 1.2.0.1073 EN 资源时已知的外观差异(点击展开)
| 问题(仅限非 1.2.0.1073 EN) | 原因 | | :---: | :---: | | **图鉴中的蓝色描述文本丢失** | 在 1.2.0.1096 中,纯文本介绍段落从 `[XXX_DESCRIPTION]` 中拆分到了一个新的 `[XXX_DESCRIPTION_HEADER]` 键中。引擎只读取 `[XXX_DESCRIPTION]`,因此这段头部文本永远不会显示。 | | **“重新开始”按钮标签缺失** | 在 1.2.0.1096 中,用于按钮标签的键 `[RESTART_LEVEL]` 被重命名为了 `[RESTART_LEVEL_BUTTON]`。 | | **未遭遇的僵尸显示为 `???`** 而不是 `(尚未遭遇)` | 字符串 `[NOT_ENCOUNTERED_YET]` 的值在 1.2.0.1096 中被更改为 `???`;旧文本被移动到了新键 `[NOT_ENCOUNTERED_YET_DESCRIPTION]` 中。 | | **疯狂戴夫的植物出售价格显示为正确值的 1/10** | 在 1.2.0.1073 中,字符串模板 `[CRAZY_DAVE_1700]` 在 `{SELL_PRICE}` 后包含一个尾随的 `0`(即 `${SELL_PRICE}0`),因为引擎传入的价格是除以 10 的。在 1.2.0.1096 中,尾随的 `0` 被移除了,因此显示的价格变成了预期金额的 1/10。 | 以上所有问题都可以通过在游戏数据旁放置的 `properties/default.xml` 文件中添加缺失或更正后的字符串条目来解决。(如果 `CMAKE_BUILD_TYPE` 是 `Debug` 则为 `ON`) | 启用**作弊键**、调试显示及其他调试功能。 | | `DO_FIX_BUGS` | `OFF` | 应用社区修复程序,修复官方 1.2.0.1073 GOTY 版本的“Bug”。[^1] 然而,这些“Bug”通常被许多玩家**视为“特性”**。 | | `CONSOLE` | `OFF`
(如果 `CMAKE_BUILD_TYPE` 是 `Debug` 则为 `ON`) | 显示控制台窗口(仅限 Windows)。 | | `BUILD_STATIC` | `OFF` | 静态链接以创建独立可执行文件(仅限带有基于 MinGW 工具链的 Windows)。对于 MSVC,请使用 vcpkg 的 `-static` triplet。 | [^1]: 当前的 `DO_FIX_BUGS` 包含以下修复: - 修复了“我是僵尸”模式中蹦极僵尸重复掉落阳光/物品的问题。 - 使被精神控制的巨人僵尸砸击敌方僵尸而不是植物。 - 使被精神控制的巨人僵尸投掷出被精神控制的小鬼僵尸(包含缩放比例、生命值和方向的修正)。 - 使被精神控制的巨人僵尸能在恐怖陶罐模式中砸碎陶罐。 - 使被精神控制的豌豆/机枪头僵尸向前方射击而不是向后。 - 使被精神控制的火爆辣椒/倭瓜僵尸伤害敌方僵尸而不是植物。 - 修正了被精神控制的倭瓜僵尸在跟踪和砸击敌方僵尸时的协调问题。 - 使被精神控制的火爆辣椒僵尸能正确清除僵王博士的技能(冰球/火球)和梯子逻辑。 - 同步了舞者僵尸的动画(修复了“女仆”位移 Bug)。 - 修复了梯子僵尸手臂恢复时的视觉故障。 - 修复了 6 行道(泳池)关卡中僵王博士的攻击(休旅车、火球/冰球)和召唤范围覆盖问题。 示例:在 **Release 构建** 中手动启用 `PVZ_DEBUG`,以便您在拥有优化性能的同时使用**作弊键**: ``` cmake -G Ninja -B build -DCMAKE_BUILD_TYPE=Release -DPVZ_DEBUG=ON ``` 如果运行这些命令未能成功构建,请创建一个 Issue 并详细说明您的问题。 ## 存档数据兼容性(用户数据和中途存档) PvZ-Portable 使用两种不同类型的存档数据: 1. **全局用户数据** (`users.dat`, `user1.dat` 等): * 存储个人资料信息、冒险模式进度、金币、禅境花园等。 * 与原版 PC 游戏格式**完全兼容**。 * 依靠设计本身已经实现了跨平台(使用显式序列化)。 2. **中途存档状态** (`game1_0.v4` 等,旧版的 `game1_0.dat` 等): * 存储使用“保存并退出”时的关卡确切状态(僵尸、子弹、植物等)。 * 游戏现在默认**仅**写入 `*.v4` 文件: * `*.v4` 文件:**跨平台格式**。完全**支持**分享这些文件以在不同的平台之间转移进度。 * `*.dat` 文件:旧版本中的**传统转储**。包含原始内存转储。**请勿**跨平台分享此文件,因为由于架构差异它会导致崩溃。 * 加载时,游戏**首选** `.v4`;`*.dat` 仅作为迁移兼容性的回退。 * 如果从旧版的 `*.dat` 加载存档,游戏会自动将其重新保存为 `*.v4`,并在成功迁移后删除旧版的 `*.dat`。 ### 为什么要有新的中途存档格式? 原版游戏的中途存档格式 (`.dat`) 实际上是将原始内存结构直接转储到磁盘上。这种方式速度快但很脆弱,因为它依赖于特定的内存布局,这在以下情况中会失效: * **不同的 CPU 架构**:x86、ARM、RISC-V、LoongArch(内存对齐方式不同)。 * **32 位与 64 位构建版本**:指针大小和结构体布局不同。 * **不同的编译器**:MSVC 对比 GCC/Clang(内存填充、枚举大小、结构体封装不同)。 因此,传统存档通常无法保证在这些变体之间互通加载。为了解决这个问题,**格式 v4** 使用 Type-Length-Value (TLV) 标签逐字段序列化游戏对象。这确保了在 x86_64 Linux 机器上保存的关卡可以在 LoongArch 或 ARM (Switch) 机器上加载而不会崩溃。 ### 格式 v4 的开发者指南 - 将新字段添加为新的 TLV ID;不要重用 ID。 - 加载旧存档时,对缺失的字段保留默认值。 - 避免对可能更改布局的数据进行原始结构体转储;首选使用固定宽度的基本类型进行显式的逐字段同步。 ### 存档编辑和转换工具 这里有一个 Python 脚本 `scripts/pvzp-v4-converter.py` 可用于检查和修改 `.v4` 存档文件。 **功能:** * **信息**:查看基本的存档统计数据(波数、阳光、僵尸等)。 * **导出为 YAML**:将二进制 `.v4` 文件转换为人类可读的 YAML 格式,以查看/编辑与游戏玩法相关的数据。 * **从 YAML 导入**:将修改后的 YAML 转换回 `.v4` 格式,并生成正确的校验和。 **用法:** ``` # 根据需要修改这些路径 # 查看基本信息 python scripts/pvzp-v4-converter.py info ~/.local/io.github.wszqkzqk/PvZPortable/userdata/game1_13.v4 # 导出为 YAML 以进行编辑 python scripts/pvzp-v4-converter.py export ~/.local/io.github.wszqkzqk/PvZPortable/userdata/game1_13.v4 level.yaml # 导入回存档 # **备份**你的原始 .v4 文件! mv ~/.local/io.github.wszqkzqk/PvZPortable/userdata/game1_13.v4 ~/.local/io.github.wszqkzqk/PvZPortable/userdata/game1_13.v4.bak python scripts/pvzp-v4-converter.py import level.yaml ~/.local/io.github.wszqkzqk/PvZPortable/userdata/game1_13.v4 ``` ## 许可证 **版权所有 (C) 2026 Zhou Qiankang
标签:AI工具, Bash脚本, C++, OpenGL ES, SDL2, 数据擦除, 植物大战僵尸, 游戏, 逆向工程还原