Files
tactical-shooter/docs/mapmaking/05-packaging-and-shipping.md
T
shawn 34507f9043 docs: community mapmaking documentation (7-file SDK guide)
- docs/mapmaking/00-index.md — SDK overview with workflow diagram
- docs/mapmaking/01-getting-started.md — template setup & first map
- docs/mapmaking/02-building-geometry.md — CSG guide & prefab reference
- docs/mapmaking/03-lighting-and-env.md — LightmapGI baking guide
- docs/mapmaking/04-validation.md — validator CLI & CI/CD usage
- docs/mapmaking/05-packaging-and-shipping.md — .pck pipeline
- docs/mapmaking/06-faq-and-troubleshooting.md — 30+ common issues
- README.md — add mapmaking SDK link to features list
2026-07-01 18:47:06 -04:00

265 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Packaging & Shipping
Once your map is built, validated, and baked, it's time to publish it to the
world. Tactical Shooter uses the **PCK** (Godot Resource Pack) format — the map
is packaged as a `.pck` file, uploaded to a registry server, and clients
download it automatically when they join a server running that map.
## Pipeline Overview
```
┌──────────┐ ┌──────────────┐ ┌──────────────┐ ┌────────────┐
│ pack_map │ → │ .pck + .json │ → │ Map Registry │ → │ Client │
│ .gd │ │ files │ → │ Server │ → │ Downloader │
└──────────┘ └──────────────┘ └──────────────┘ └────────────┘
(editor (artifacts) (HTTP serving) (autoload)
tool)
```
## Step 1: Package the Map
The `pack_map.gd` script (at `scripts/map_packaging/pack_map.gd`) is a Godot
editor tool that exports a `.tscn` scene as a standalone `.pck` resource pack.
### Usage
From the **map template project** (not the main game project):
```bash
cd maps/my_first_map/
godot --headless --script /path/to/scripts/map_packaging/pack_map.gd \
--map=res://de_my_map.tscn
```
> Replace `/path/to/` with the actual path to the tactical-shooter repository
> root, or copy `pack_map.gd` into your map project's `scripts/` directory.
### What It Does
1. Loads the specified `.tscn` scene
2. Recursively collects all dependencies (materials, textures, meshes, etc.)
3. Exports them to `user://packed_maps/de_my_map.pck`
4. Writes a metadata file `user://packed_maps/de_my_map.json`
### Output Files
```
user://packed_maps/
├── de_my_map.pck # Binary resource pack (~110 MB for a typical map)
└── de_my_map.json # JSON metadata (machine-readable)
```
**Metadata example** (`de_my_map.json`):
```json
{
"map_name": "de_my_map",
"source_scene": "res://de_my_map.tscn",
"godot_version": {
"major": 4,
"minor": 2,
"string": "4.2"
},
"packed_at": "2026-06-25T14:30:00"
}
```
### Requirements
- The map scene must use **local resources** only (relative `res://` paths)
- External dependencies (game shared assets like weapon models, player
models) should stay in the base game — the `.pck` is **additive** content
- The `.pck` contains only the map's unique assets, not the entire game
### From the Editor
You can also run `pack_map.gd` from the Godot editor:
1. Open your map project in Godot
2. Open your map scene (`de_my_map.tscn`)
3. **Project → Tools → Pack Current Map** (if configured)
4. The script detects the active scene and exports it
## Step 2: Set Up the Map Registry Server
The registry server is a lightweight Python HTTP server
(`scripts/map_packaging/map_registry_server.py`) that:
- Serves `.pck` files for download
- Provides a JSON `/maps` endpoint listing available maps
- Auto-scans the maps directory every 5 seconds
- Computes and serves SHA-256 checksums for integrity verification
### Starting the Server
```bash
cd /path/to/tactical-shooter
# Default: port 8090, maps from ./packed_maps/
python3 scripts/map_packaging/map_registry_server.py
# Custom configuration
python3 scripts/map_packaging/map_registry_server.py \
--port 8080 \
--maps-dir /data/tactical-shooter-maps \
--verbose
```
**Environment variables:**
| Variable | Overrides | Default |
|----------|-----------|---------|
| `MAP_REGISTRY_PORT` | `--port` / `-p` | 8090 |
| `MAP_REGISTRY_MAPS` | `--maps-dir` / `-d` | `./packed_maps/` |
### API Endpoints
| Endpoint | Method | Description |
|----------|--------|-------------|
| `GET /` | — | Server info and endpoint documentation |
| `GET /maps` | — | JSON list of all available maps with metadata |
| `GET /maps/<name>.pck` | — | Download map `.pck` binary |
| `GET /maps/<name>.json` | — | Download per-map metadata |
| `OPTIONS /maps` | — | CORS preflight |
**Example responses:**
```
GET /maps
```
```json
{
"maps": [
{
"name": "de_dust2",
"size": 5432100,
"version": 1,
"description": "Classic competitive map",
"checksum_sha256": "a1b2c3d4...",
"packed_at": "2026-06-25T14:30:00"
}
],
"server_name": "Tactical Shooter Map Registry",
"server_version": "1.0.0",
"map_count": 1
}
```
```
GET /maps/de_dust2.pck
```
→ Returns the `.pck` binary file as an octet-stream download.
### Deployment Options
- **Local dev:** Run on the same machine as the game (default `127.0.0.1:8090`)
- **Server host:** Run on a public server alongside the master server
- **Docker:** Wrap in a Docker container for easy deployment
- **Systemd service:** Create a service file for production hosting
**Systemd service example:**
```ini
[Unit]
Description=Tactical Shooter Map Registry
After=network.target
[Service]
Type=simple
User=tactical
WorkingDirectory=/opt/tactical-shooter
ExecStart=/usr/bin/python3 scripts/map_packaging/map_registry_server.py \
--port 8090 --maps-dir /data/tactical-maps
Restart=on-failure
[Install]
WantedBy=multi-user.target
```
## Step 3: Upload Your Map
1. Copy the `.pck` and `.json` files to the registry server's maps directory:
```bash
cp user://packed_maps/de_my_map.pck /data/tactical-maps/
cp user://packed_maps/de_my_map.json /data/tactical-maps/
```
2. The server auto-detects new files within 5 seconds
3. Verify via `curl http://your-server:8090/maps`
## Step 4: Client Downloads
The client uses `MapDownloader` (autoload at `client/scripts/map_downloader.gd`)
to fetch and load maps at runtime.
### How It Works
1. Player joins a server that specifies a map name
2. The client checks its local cache (`user://maps/manifest.json`)
3. If the map is not cached, `MapDownloader.fetch_map_list()` polls
the registry server to verify the map exists
4. `MapDownloader.download_map(name)` downloads the `.pck` to `user://maps/`
5. `ProjectSettings.load_resource_pack()` loads it into the game
6. The server changes to the new level
### Map Caching
```
user://maps/
├── de_dust2.pck # Cached map binary
├── de_inferno.pck # Another cached map
└── manifest.json # Cache index
```
**Cache behaviour:**
- Maps are cached to disk after download (survives restarts)
- The manifest tracks version numbers for staleness checks
- `MapDownloader.remove_map(name)` clears a specific map
- `MapDownloader.clear_cache()` removes all cached maps
### Configuration
The `MapDownloader` autoload can be configured in-game:
```gdscript
# Set the registry server URL (override default http://127.0.0.1:8090)
MapDownloader.registry_url = "http://maps.myserver.com:8090"
```
The URL can also be set via the `MAP_REGISTRY_URL` environment variable,
which is read in `_ready()`.
### Signals
```gdscript
# Register for map lifecycle events
MapDownloader.map_list_loaded.connect(_on_map_list)
MapDownloader.map_download_progress.connect(_on_download_progress)
MapDownloader.map_download_complete.connect(_on_download_done)
MapDownloader.map_loaded.connect(_on_map_loaded)
```
## Full Pipeline Example
```bash
# 1. Package from the template project
cd maps/my_first_map
godot --headless --script ../../scripts/map_packaging/pack_map.gd \
--map=res://de_my_map.tscn
# 2. Start registry server
cd ../..
python3 scripts/map_packaging/map_registry_server.py --port 8090 &
# 3. Deploy map
cp ~/.local/share/godot/app_userdata/MapTemplate/packed_maps/de_my_map.pck \
scripts/map_packaging/packed_maps/
cp ~/.local/share/godot/app_userdata/MapTemplate/packed_maps/de_my_map.json \
scripts/map_packaging/packed_maps/
# 4. Verify
curl -s http://localhost:8090/maps | python3 -m json.tool
# 5. In-game: connect to server and play the map
```
## Next Steps
- [FAQ & Troubleshooting](06-faq-and-troubleshooting.md) — common issues