Files
simple-updater/README.md
T

143 lines
4.9 KiB
Markdown

# Simple Universal Game Updater
A simple, self-hosted updater for distributing game client files. Consists of three parts:
- **`updater.py`** — the client-side app (compiled to `updater.exe`) that players run. Checks the server for changed files and downloads only what's needed.
- **`server.py`** — a lightweight HTTP server that serves client files and manifests.
- **`generate_manifest.py`** — a script you run on your build machine to generate the manifest the server distributes.
- **`generate_key.py`** — a helper to generate access keys (see [Access keys](#access-keys) below).
Works with any game — just fill in the configuration blocks at the top of each script.
## How it works
1. You put your game's files in a folder on the server (e.g. `game_client/`).
2. You run `generate_manifest.py` on that folder. It walks the folder, hashes every file (MD5), and writes a `manifest.json` listing `relative/path: hash` for every file.
3. `server.py` serves that folder over HTTP, keyed by an access key defined in `config.json`.
4. Players run `updater.exe`. It downloads the server's `manifest.json`, compares hashes against their local files, and downloads anything missing or different.
5. Once everything matches, the "Play" button launches the game executable.
## Setup
### 1. Server
Install Python 3 (no external dependencies needed — everything uses the standard library).
Generate an access key for each client version you want to distribute:
```bash
python generate_key.py
```
This prints a random 64-character hex string. Generate one per client (e.g. one for `main`, one for `test`).
Edit `config.json`:
```json
{
"host": "0.0.0.0",
"port": 3232,
"clients": {
"<your-generated-hex-key>": "game_client",
"<another-generated-hex-key>": "game_client_test"
}
}
```
- `host` / `port` — what the server listens on.
- `clients` — maps an access key to the folder (relative to `server.py`) that key serves.
Put your game files in the folders referenced above (`game_client/`, etc.), then generate the manifest for each:
```bash
python generate_manifest.py game_client
python generate_manifest.py game_client_test
```
Re-run this after every update to the client files, then start (or restart) the server:
```bash
python server.py
```
Files become available at `http://<server-address>:<port>/<access-key>/...`.
### 2. Updater (client)
Edit the configuration block at the top of `updater.py`:
```python
GAME_NAME = "My Game"
SERVER_ADDRESS = "update.mygame.com" # domain or IP
SERVER_PORT = "3232"
USE_HTTPS = False
CLIENT_KEYS = {
"Main": "<same-hex-key-as-in-server-config.json>",
"Test": "<same-hex-key-as-in-server-config.json>",
}
DEFAULT_CLIENT = "Main"
GAME_EXE_RELATIVE_PATH = os.path.join("system", "game.exe")
BANNER_RELATIVE_PATH = "banner.png"
ICON_RELATIVE_PATH = "icon.ico"
```
- `SERVER_ADDRESS` accepts either a domain name or a raw IP — nothing else needs to change.
- `CLIENT_KEYS` maps a friendly name shown in the UI to the actual access key sent in the request URL. Keys must match `config.json` on the server exactly.
- `GAME_EXE_RELATIVE_PATH` is where the updater looks for the game's executable, relative to the folder the updater itself is placed in.
Then compile with your favorite tool, e.g. [PyInstaller](https://pyinstaller.org/):
```bash
pyinstaller --onefile --noconsole --icon=icon.ico --add-data "banner.png;." --add-data "icon.ico;." updater.py
```
Ship the resulting `updater.exe` alongside the game folder.
## Access keys
Client folders are addressed by a long random hex key instead of a plain name like `main`, so the update path isn't obvious or easy to stumble on by guessing.
**This is obscurity, not real security.** The key has to live inside `updater.exe` for it to work, and anyone motivated enough to disassemble the executable or inspect network traffic can recover it. Don't rely on it to gate anything sensitive.
If a key leaks and you want to rotate it:
1. Generate a new key with `generate_key.py`.
2. Update it in the server's `config.json`.
3. Update it in `updater.py`'s `CLIENT_KEYS`.
4. Rebuild and redistribute `updater.exe`.
No folder renaming or manifest regeneration needed.
## Ignoring files during manifest generation
Edit the configuration block at the top of `generate_manifest.py`:
```python
IGNORE_FILES = {
MANIFEST_FILENAME,
"updater.exe",
"Option.ini",
"WindowsInfo.ini",
}
IGNORE_FOLDERS = {
"screenshots",
"logs",
"replays",
}
IGNORE_EXTENSIONS = {
".log",
}
```
Add any player-specific files (settings, saves, screenshots, logs) here so the updater never overwrites or deletes them.
## Notes / limitations
- File integrity is checked with MD5 — fine for detecting changed files, not intended as a cryptographic guarantee.
- The server has no built-in rate limiting or HTTPS; put it behind a reverse proxy (nginx, Caddy) if you need either.
- `updater.py` uses Tkinter for the UI, which ships with most standard Python installs on Windows.