Files
website/scripts/build-pubg-tiles.py
Stan Runge 0fe0d36f87
All checks were successful
Deploy production / deploy (push) Successful in 1m15s
PUBG drop map: live squad map with WebSocket rooms
- server.js wraps Bun.serve to add /ws/<channel> upgrades (same server and port) and
  serve the map tiles from the host mount; Dockerfile now runs bun ./server.js
- ws hub (channel registry, origin check) + pubg-map channel: rooms by unguessable
  code, validated + rate-limited messages, per-room write queue, presence
- games.pubg_rooms / pubg_matches / pubg_markers; per-match sessions with history
- /trackers/games/pubg/map hub (owner: rooms, landings over time, history) and
  /trackers/games/pubg/map/<code> fullscreen Leaflet map (all 11 maps)
- deploy-remote.sh bind-mounts ~/pubg-maps; scripts/build-pubg-tiles.py rebuilds it
2026-10-25 22:46:30 +00:00

42 lines
2.0 KiB
Python

#!/usr/bin/env python3
"""Build the PUBG drop map tiles from PUBG's official api-assets (github.com/pubg/api-assets,
used under the PUBG Developer API terms; © KRAFTON). Not in the repo or image (~115 MB):
the output goes to the host directory that scripts/deploy-remote.sh bind-mounts at /pubg-maps.
python3 scripts/build-pubg-tiles.py [out_dir] (default ~/pubg-maps; needs Pillow)
Each 8192 px map becomes 512 px WebP tiles, zoom 0 (whole map) to 4 (full resolution),
<out>/<map>/<z>/<x>/<y>.webp, plus a 384 px <out>/<map>/thumb.webp."""
import os, sys, tempfile, urllib.request
from multiprocessing import Pool
from PIL import Image
Image.MAX_IMAGE_PIXELS = None
T = 512
BASE = 'https://media.githubusercontent.com/media/pubg/api-assets/master/Assets/Maps'
# Keep in sync with MAPS in src/lib/pubg-map/shared.ts.
MAPS = {'erangel': 'Erangel', 'miramar': 'Miramar', 'sanhok': 'Sanhok', 'vikendi': 'Vikendi',
'taego': 'Taego', 'deston': 'Deston', 'rondo': 'Rondo', 'karakin': 'Karakin',
'paramo': 'Paramo', 'haven': 'Haven', 'camp-jackal': 'Camp_Jackal'}
OUT = os.path.expanduser(sys.argv[1] if len(sys.argv) > 1 else '~/pubg-maps')
def run(slug):
with tempfile.NamedTemporaryFile(suffix='.png') as f:
urllib.request.urlretrieve(f'{BASE}/{MAPS[slug]}_Main_High_Res.png', f.name)
src = Image.open(f.name).convert('RGB')
for z in range(4, -1, -1):
size = T * 2**z
im = src if size == src.width else src.resize((size, size), Image.LANCZOS)
for x in range(2**z):
d = f'{OUT}/{slug}/{z}/{x}'
os.makedirs(d, exist_ok=True)
for y in range(2**z):
im.crop((x*T, y*T, (x+1)*T, (y+1)*T)).save(f'{d}/{y}.webp', 'WEBP', quality=78, method=5)
src.resize((384, 384), Image.LANCZOS).save(f'{OUT}/{slug}/thumb.webp', 'WEBP', quality=75)
return slug
if __name__ == '__main__':
with Pool(4) as p:
for s in p.imap_unordered(run, list(MAPS)):
print(s, flush=True)