# t5de Patches for the IMVU Classic client. This repository holds only the patches and the tooling; the client itself is downloaded from IMVU and decompiled locally, and never committed. ## Setup Needs Python 3.12+, git, and 7-Zip (`7z` on PATH, or installed in its default location on Windows). `t5de build` also needs Python 2.7, the client's own Python: found through the `py` launcher on Windows, `python2.7` or `python2` on PATH, or the `T5DE_PYTHON27` environment variable. ```sh python -m venv .venv .venv/Scripts/pip install -e . # Linux/macOS: .venv/bin/pip t5de setup ``` `t5de setup` downloads the client version pinned in `t5de.toml` (checksum-verified), extracts it, and creates `work/`: a git repository whose `base` commit is the decompiled Python (`library/`) and UI (`imvuContent/`), with every patch in `patches/` applied on top as one commit each. ## Writing patches `work/` is a normal git repository. Edit files, then commit; each commit is one patch. ```sh cd work # ...edit library/imvu/... or imvuContent/... git commit -a -m "Show seconds in chat timestamps" -m "Why, and what it changes." \ --trailer "T5de-Id: chat-seconds" --trailer "T5de-Group: chat" cd .. t5de save # export every commit after `base` to patches/ ``` Users choose which patches to apply, so every patch needs these trailers in its commit message (the subject is the title users see, the rest of the body the description): - `T5de-Id:` a short lowercase-words id, unique among the patches. - `T5de-Name:` (optional) the patch's name in the installer, a few words in Title Case like "More Room Filters"; without it the installer shows the subject. The subject and body appear when users hover over it. - `T5de-Group:` the installer's section for an optional patch: `general`, `shop`, `rooms`, `avatars`, `chat` or `renderer`; or `core` or `privacy` (always applied; also add `T5de-Required: true`). - `T5de-Depends: id, id` (optional): patches this one needs. Required when it changes a function or UI file another patch changes, or uses a function another patch adds; `t5de build` tells you. To change an existing patch, amend or fixup its commit (`git rebase -i base`), then `t5de save`. Commit the files in `patches/` to this repository. `t5de setup --force` rebuilds `work/` from scratch; run `t5de save` first, or local commits are lost. Patches can also add files of t5de's own (never IMVU's) to the client folder: commit them under `client/` in `work/`, and the patcher writes them into the install (`client/imvu.ico` replaces the client's window icon). Python patches can change or add functions and methods, but not module-level or class-level code: only the functions a patch touches are recompiled, because recompiling whole decompiled modules isn't reliable. The original of every replaced definition stays callable as `_t5de_original_` (`self._t5de_original_` for methods), so a patch can wrap IMVU's code instead of rewriting it; it's always IMVU's original, even when other patches change the same function. `t5de build` warns when a patched function's decompiled original doesn't recompile to IMVU's bytecode; wrap those rather than editing the decompiled text. ## Building ```sh t5de build ``` Writes the patch bundle (`build/bundle/manifest.json`, also available on its own with `t5de bundle`), then has the patcher apply every patch to the client into `build/IMVUClient/`. The patcher is Go: `t5de build` runs it with `go run`, or set `T5DE_PATCHER` to a built `t5de-patcher`. Run `build/IMVUClient/IMVUClient.exe` to test it, with a throwaway IMVU account. The patched client keeps its settings and logs apart from an installed original client (`HKCU\Software\T5DE` and `%APPDATA%\T5DE`), so both can be used side by side. Every request to IMVU's reporting endpoints that the patched client refuses is logged as `t5de: blocked request to` in `%APPDATA%\T5DE\IMVULog.log`. ## Patcher `patcher/` is the Go patcher users run on their own copy of IMVU Classic (an installer wizard is to come). It verifies the client, then writes a patched copy with the chosen patches; the original is untouched: ```sh cd patcher go run ./cmd/t5de-patcher list -bundle ../build/bundle/manifest.json go run ./cmd/t5de-patcher apply -bundle ../build/bundle/manifest.json \ -client -out -patches room-filters,no-ads ``` Required patches are always applied; `-patches` picks optional ones (default all, empty for none). On Windows, `install` does what the installer will: it finds IMVU Classic (or takes `-client`), patches a copy into `%LOCALAPPDATA%\T5DEClient` (or `-dir`), keeps a copy of itself and the bundle there, and adds a Start menu shortcut (`-desktop` for one on the desktop too) and an "Apps & features" entry, all for the current user without admin rights. `uninstall` (also what "Apps & features" runs) removes them, and with `-remove-data` the patched client's settings and logs: ```sh go run ./cmd/t5de-patcher install -bundle ../build/bundle/manifest.json -desktop go run ./cmd/t5de-patcher uninstall ``` `cmd/t5de-setup` is the same as a wizard (Wails, with a plain HTML/CSS/JS page in `frontend/`): install, and change, repair or uninstall an existing install. Release builds carry the bundle inside (copied to `cmd/t5de-setup/bundle/manifest.json` before building); in development pass it: ```sh go build -tags desktop,production -ldflags "-H=windowsgui" -o t5de-setup.exe ./cmd/t5de-setup ./t5de-setup.exe -bundle ../build/bundle/manifest.json ``` ## Tests ```sh .venv/Scripts/pip install -e ".[test]" .venv/Scripts/python -m pytest ``` Tests that need Python 2.7 or a built client (`t5de setup` and `t5de build`) are skipped when those are missing; set `T5DE_REQUIRE_ALL=1` to make them fail instead, as CI does. ## CI `.gitea/workflows/ci.yml` runs the tests, a fresh `t5de setup` (which checks the base commit against `t5de.toml`) and `t5de build`, then the client tests, on every push to `main` and every pull request. The built client is never uploaded: it contains IMVU's client. Every run then builds `T5DE-Setup.exe` (the patcher and the bundle, no IMVU files) and attaches it to the run. Pushes to `main` publish it as the `nightly` pre-release, replacing the previous one; pushing a `vX.Y.Z` tag publishes release X.Y.Z: ```sh git tag v0.1.0 && git push origin v0.1.0 ``` Release builds send anonymous usage statistics (Aptabase) and crash reports (Bugsink) when users allow it, to the servers in the repository secrets `APTABASE_HOST`, `APTABASE_APP_KEY` and `BUGSINK_DSN`. Builds without them, including local ones, send nothing. Installs update themselves: when T5DE starts, it looks for a newer build on its channel (releases for releases, the nightly for nightlies) and offers it in the client's update dialog. Updating downloads the new setup, which reapplies the install's patches and settings. Local builds don't update. `.gitea/workflows/imvu-update.yml` runs `t5de check-update` daily and opens an issue when imvu.com has a newer IMVU Classic release than the one pinned in `t5de.toml`.