Open-source project
wszqkzqk/PvZ-Portable avatar
wszqkzqk/PvZ-Portable

PvZ-Portable and the work of reimplementing Plants vs. Zombies for modern hardware

A cross-platform reimplementation of Plants vs. Zombies by the community. Aiming to bring 100% authentic experience of GOTY edition.

838 stars177 forksC++LGPL-3.0

At a glance

What is it?
PvZ-Portable is a community reimplementation of Plants vs. Zombies: Game of the Year Edition written in C++ against SDL2 and OpenGL ES 2.0. It ships no game assets, targets everything from Linux desktops to WebAssembly and Switch, and reads and writes save data formats that are the fiddliest part of the job.
Who is it for?
PvZ-Portable is worth adopting for engineers studying cross-platform porting, for teams who want to run a legally owned copy on a device the original never shipped to, and for anyone maintaining the `.v4` save format or the MO3 audio path. It is the wrong choice if you want bundled game content, if you are on Haiku and need music, or if your iOS distribution must be signed, since the IPA is unsigned and sideload only.
Can I use it commercially?
Yes, with conditions. LGPL-3.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A reimplementation that deliberately ships no game content

PvZ-Portable reproduces Plants vs. Zombies: Game of the Year Edition in C++, and the repository contains no copyrighted assets. No images, no music, no fonts. The rule for users is simple and non-negotiable: supply your own `main.pak` file and a `properties/` folder taken from a legally purchased copy, and place them next to the `pvz-portable` executable, which then searches for resources relative to that location.

That constraint is what makes the project legally and technically interesting at the same time. The code is a manual reimplementation derived from community research such as the PvZ Wiki and PvZ Tools, and the author states plainly that reverse engineering was never used and that code generated directly through reverse engineering will not be accepted. The stated purpose is educational: cross-platform porting techniques, engine modernization, and how classic game logic adapts to different hardware.

So the audience is engineers, not players looking for a free copy of the game. The project is not affiliated with, authorized or endorsed by PopCap Games or Electronic Arts, and it says so plainly.

Why OpenGL ES 2.0 became the rendering target

Rendering goes through SDL with OpenGL ES 2.0, falling back to desktop OpenGL 2.1. The stated reasoning is portability rather than fidelity: GLES 2.0 is treated as the common subset of modern GPU APIs, so every desktop OpenGL 2.1 or later driver, mobile GPU and console supports it inherently, which lets the build work out of the box without extra dependencies.

There is an escape hatch. ANGLE can optionally be used to translate calls to DirectX, Metal or Vulkan when a platform needs it, which covers the cases where the native path is a poor fit. The project also adds window resizing, something the original game did not allow, and disables caching on console platforms with very little RAM in order to save memory.

A C++ codebase reaching this many targets does its cross-platform work through standard library choices the feature list calls out: `std::thread` for threading and `std::filesystem` for file system access. The repository also carries a `.clangd` file and a `CMake/` directory, and the build pulls dependencies through vcpkg with `vcpkg.json` and `vcpkg-configuration.json` at the root.

The audio fork and the MO3 format problem

The original game's music and sound are stored in formats the stock audio path does not handle well, and PvZ-Portable solves this with a fork rather than a plugin. The project uses SDL Mixer X, and specifically a fork of it that adds compatibility with the MO3 format by routing through libopenmpt. That fork lives inside the tree under `SexyAppFramework/sound/SDL-Mixer-X`, so the audio behaviour is versioned with the project rather than depending on a system package.

The practical consequence is that a build on a supported platform can play the game's original music tracks, while a build on a platform with a thinner audio stack may not. The platform table shows exactly this pattern: Haiku is marked as partially working with no music, and every other listed target is marked as working.

Keeping the fork in-tree is a real upgrade cost decision. It also means the audio path is not a plain dependency upgrade, so a team considering this codebase for a long-lived fork should look at that directory before planning a dependency refresh.

Reading user*.dat and writing the .v4 save format

Save handling is where ports usually break, and this one puts unusual effort into it. The project is compatible with the original GOTY global user data, which covers profile information, adventure progress, coins and the Zen Garden, stored in `user*.dat` files. It also fixes the 2038 year problem while keeping that compatibility, so timestamps written by the port survive the rollover that broke older 32-bit time handling.

Alongside the original format sits a portable mid-level save format called `.v4`, meant for sharing mid-level saves between Windows, Linux, macOS, Android and Switch. It supports export and import of `.v4` files to and from a human-readable YAML representation for easy editing, which is a pragmatic choice for people who want to move a save by hand rather than through a menu.

The feature list also claims save data compatibility across endianness. It is careful about the limits of that claim: big-endian platforms are described as theoretically supported but untested due to a lack of hardware. The project supports little-endian and big-endian systems, and UTF-8 is used uniformly inside the program, with Unicode path support on all platforms.

Where the port goes past what the original shipped

Beyond raw compatibility, the project re-implements details that the retail version left locked away. The Hidden Limbo Page, an unlockable page of additional levels in the original game, is restored, and the unlock procedure is specific: open the Mini-Games, Puzzle, Survival selection screen and tap any blank area five times in rapid succession. That kind of fidelity work is only possible from a behavioral description of the game rather than from a copy of the shipped binaries.

Language support follows the same approach. The port reads official GOTY resource data in Chinese, German, Spanish, French and Italian, so a player with the corresponding retail resources gets a localized game without the port carrying its own translations.

The build matrix is the third area of extra reach. 32-bit and 64-bit builds both exist, and the CPU list named in the feature list covers i686, x86_64, aarch64, riscv64 and loongarch64. Mobile and console targets sit alongside desktop ones, which is unusual for a project of this size and explains why so much of the code is about portability rather than gameplay.

Deterministic session recording and playback

One of the more unusual entries in the feature list is the ability to record gameplay sessions and replay them deterministically, and the README dedicates a section to it under the heading Recording and Playing Back Gameplay. A deterministic replay of a tower defence game is not a trivial feature, since a match depends on a fixed sequence of player inputs, a fixed simulation, and a fixed rendering of the result.

The value for an engineer reading the code is that a replay mechanism is a forcing function. It means the simulation has to be reproducible across runs, and that a bug report can come with a replayable file rather than a description of what the reporter saw. It also makes performance comparison possible in principle, since two runs of the same input sequence can be compared.

The README excerpt available here states the capability and links to its own section for details, and it does not describe the file format of a recording, so the on-disk representation cannot be confirmed from the top-level documentation. Anyone building tooling around replays would need to read the section itself before assuming a format.

Where the files live on each platform

The path strategy is the quiet difference between a port that works and a port that fights its host. On Linux, Windows, macOS and the BSD family, resources sit in the executable directory while writable files, including saves, go to per-user app data. That split is what allows a read-only application directory, such as a system package location, to work at all.

Mobile and embedded targets use different conventions. Android writes to `Android/data/io.github.wszqkzqk.pvzportable/files/`, iOS and iPadOS use the app documents directory reachable from the Files app, the Nintendo Switch build keeps everything under `sdmc:/switch/PvZPortable`, and the WebAssembly build keeps saves in browser IndexedDB while resources are uploaded at runtime, which is why that target requires an HTTP server rather than a local file.

Two caveats are stated plainly. The iOS build works only as an unsigned IPA installed by sideloading. On real Switch hardware the build works, but the Kenji-NX emulator crashes on boot. Haiku runs without music.

Building across targets, and where the project actually stands

The repository is organised for multi-target work. Alongside the `src/` tree there are `android/`, `ios/` and `wasm/` directories for the platform-specific pieces, an `archlinux/` directory for packaging, plus `scripts/`, `tools/` and a top-level `CMakeLists.txt` fed by vcpkg manifests. The README points readers to the project page for the browser build, and offers a no-install path at `pvz-portable.html`, which still needs game data supplied by the player. The top-level documentation does not spell out a full build command sequence, so a new contributor should follow the build files in the repository rather than expect a copy-paste recipe.

The last push to the repository was on 2026-10-19, and the project is not archived. Recent tagged releases include 0.2.5 on 2026-10-10, 0.2.4 on 2026-09-24 and 0.2.3 on 2026-09-09, a pace of roughly one tagged release per month across those three points.

Licensing is LGPL-3.0, with a COPYING file and a LICENSE file at the root. That license carries obligations that differ between using the code as a library and shipping a modified binary, so any team planning to fork it should read the license text and the bundled copy rather than rely on a summary. The practical starting point for anyone evaluating this project is that the code is open and the content is not.

Editorial conclusion

PvZ-Portable is worth adopting for engineers studying cross-platform porting, for teams who want to run a legally owned copy on a device the original never shipped to, and for anyone maintaining the `.v4` save format or the MO3 audio path. It is the wrong choice if you want bundled game content, if you are on Haiku and need music, or if your iOS distribution must be signed, since the IPA is unsigned and sideload only. Before committing, confirm you can supply `main.pak` and `properties/` from a copy you bought, and check the per-platform status notes in the README, because several targets carry known rough edges.

Frequently asked questions

Do I need to supply my own Plants vs. Zombies game files for PvZ-Portable?

Yes. The repository contains no copyrighted game assets, so you must provide `main.pak` and the `properties/` folder from a legally purchased copy of Plants vs. Zombies: Game of the Year Edition and place them next to the `pvz-portable` executable. The browser build also needs your own game data files.

Which platforms does PvZ-Portable support?

The README lists Linux, Windows, macOS, the BSD family, Android, iOS and iPadOS, WebAssembly in the browser, and Nintendo Switch. Haiku is only partially working because it has no music, the iOS build is an unsigned IPA for sideloading only, the web build requires an HTTP server, and the Kenji-NX emulator crashes on boot.

How do I build PvZ-Portable from source?

The repository carries a CMakeLists.txt, a CMake directory, vcpkg.json and vcpkg-configuration.json, plus per-platform folders for android, ios and wasm, and an archlinux folder for packaging. The README points to INSTALL-style guidance through the project pages, and it does not publish a full build command sequence in the top-level documentation.

Where are PvZ-Portable save files stored?

On desktop platforms such as Linux, Windows, macOS and BSD, resources live in the executable directory while writable files and saves go to per-user app data. Android uses `Android/data/io.github.wszqkzqk.pvzportable/files/`, iOS uses the app documents directory, the Switch build uses `sdmc:/switch/PvZPortable`, and the web build keeps saves in IndexedDB.

Was PvZ-Portable built by reverse engineering the original game?

No. The README states the code is a manual reimplementation based on publicly available information and community research such as the PvZ Wiki and PvZ Tools, that the author never reverse engineered the program, and that code generated directly through reverse engineering will not be accepted.

Official sources

  1. License: LGPL-3.0
  2. Project website
  3. README
  4. Releases
  5. wszqkzqk/PvZ-Portable on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/wszqkzqk-pvz-portable.svg)](https://hysenlabs.com/projects/wszqkzqk-pvz-portable)

Was this useful?