CoOp:Anything
게임을 검색해 협동 플레이 가능한 모드·단계·품질·커뮤니티 평점을 확인합니다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A self-hosted, game-agnostic multiplayer backend. One Docker stack on your VPS gives you:
POST /api/setup/recommend with a profile (players, update rate, latency target, data model) and apply the result with PUT /api/setup: room types, limits, servers, leaderboards, storage rules and the server script. The game's Setup tab then shows the expected numbers next to the measured ones (average and peak players, players per room, update rate, tick, ping, traffic).quickJoin), host election and migration, kick/ban, locking, passwords, reconnects that keep the player's slot.predict(), connect and join in one round trip, per-player ping in the dashboard, and kernel tuning (tune-network.sh).| Game detail: key, Claude prompt, live rooms | Room inspector: players, data, live state |
|---|---|
Demo game (/demo): five players in one room. The host spawns coins and validates every pickup.
server/ Node 24 server (ws + node:sqlite), Dockerfile, smoke test
client/ multiplayer.js: browser/Node SDK (served at /sdk.js)
docs/ Dashboard (GitHub Pages root, also served at /)
examples/ demo.html: Coin Arena demo (served at /demo)
MULTIPLAYER.md Integration guide to hand to any Claude chat
ssh root@YOUR_VPS_IP
git clone https://github.com/ZDStudios/Multiplayer-Game-System.git mp && cd mp # or scp this folder up
sh deploy.sh
deploy.sh installs Docker if it's missing and creates .env with a random ADMIN_TOKEN. It sets DOMAIN=<ip-with-dashes>.sslip.io, a free hostname that resolves to your IP, so HTTPS works without buying a domain. It also records the VPS's public IP as PUBLIC_IP (WebRTC advertises it to browsers). It then opens ports 80, 443, 8081/udp and 8082/udp in ufw and runs docker compose up -d --build. To use your own domain, point an A record at the VPS, set DOMAIN= in .env, and run docker compose up -d.
Make sure ports 80 and 443 (TCP) and 8081 and 8082 (UDP) are open in the Hostinger panel firewall too. UDP goes straight to the container, not through Caddy/Traefik. If those UDP ports are blocked, everything still works over WebSocket.
| URL | What it is |
|---|---|
https://DOMAIN/ | Dashboard |
https://DOMAIN/demo | Demo game. Open it from a game's page in the dashboard so the key is filled in. |
https://DOMAIN/sdk.js | Client SDK |
https://DOMAIN/MULTIPLAYER.md | Integration guide |
wss://DOMAIN/ws | WebSocket endpoint (signalling + fallback) |
udp://DOMAIN:8081 | Raw UDP link for native/Node clients |
udp://DOMAIN:8082 | WebRTC data channels (all peers multiplexed on one port) |
https://DOMAIN/health | Health check |
Operations:
docker compose logs -f mp # logs
docker compose up -d --build # update after git pull
docker compose exec mp cat /data/mp.db > backup.db # or back up the mp-data volume
Latency is mostly distance plus routing, so host where your players are. Measured from Perth: Sydney ~51 ms, Melbourne ~59 ms, Singapore ~179 ms, Kuala Lumpur ~182 ms. For players all over Australia, Sydney is the best single location. Any Linux VPS with a public IPv4 works (x64 or arm64, 1 vCPU / 1 GB is plenty to start), with Ubuntu 22.04 or 24.04.
ssh-keygen -t ed25519 && ssh-copy-id root@OLD_IPgit clone <your-repo-url> mp && cd mp
sh migrate.sh root@OLD_IP
This installs Docker, then copies the database and the admin token. Game keys, player identities, accounts, storage and leaderboards all carry over. The old server is left stopped; the script prints a rollback command.DOMAIN= in .env, then run docker compose up -d. Nothing changes for players.SERVER_URL in your games and in the dashboard login.sudo sh tune-network.sh.sudo sh tune-network.sh # BBR + fq, low TCP send buffering, no slow-start after idle (persists across reboots)
The biggest factor is the network path between players and the VPS. Check the Ping / link column in the dashboard; it also shows which link each player ended up on. If players are far from the server or their ISP routes badly, put the domain behind Cloudflare (proxied DNS record; WebSockets work on the free plan). Cloudflare doesn't proxy raw UDP, so set UDP_HOST to a DNS-only record (or the IP) when you do this. Cloudflare's backbone often beats ISP routing. Measured from Perth to the Kuala Lumpur VPS: 314 ms direct vs 239 ms through Cloudflare. Hosting the VPS in the same region as your players matters most of all.
Push the repo, then go to Settings → Pages → Deploy from branch → main / /docs. Open the Pages URL and enter your server URL and admin token. They're stored only in that browser's localStorage. The same dashboard is also served from the VPS at /.
MULTIPLAYER.md. Claude can also fetch the guide from https://DOMAIN/MULTIPLAYER.md.cd server && npm install && npm start # http://localhost:8080, admin token printed on first run
npm test # end-to-end smoke test (106 checks: rooms, setup API, public servers, open-world interest management, room types, storage, leaderboards, social, inbox, matchmaking, chat, UDP/WebRTC, packet loss, failover)
.env)| Var | Default | |
|---|---|---|
DOMAIN | – | Hostname for Caddy TLS |
ADMIN_TOKEN | auto-generated, printed in logs | Dashboard and admin API bearer token (≥16 chars) |
OPEN_GAMES | false | When true, any unknown key ≥8 chars auto-creates a game. Dev convenience only. |
RATE_LIMIT / RATE_BURST | 60 / 200 | Messages per second per connection |
MAX_MSG_BYTES | 65536 | Maximum size per message and per stored value |
RECONNECT_GRACE_MS | 15000 | How long a dropped player keeps their room slot |
MAX_CONNS_PER_IP | 50 | |
PUBLIC_IP | – | Public IPv4 advertised in WebRTC candidates. Required in Docker for browsers to reach WebRTC. |
UDP_PORT | 8081 | Raw UDP transport, 0 = off |
RTC_PORT | 0 (random ports) | WebRTC on one multiplexed UDP port (compose sets 8082) |
WEBRTC | true | false turns off WebRTC |
UDP_HOST | host the client connected to | Host clients send raw UDP to |
ICE_SERVERS | – | Comma-separated STUN/TURN URLs for the server's WebRTC peer |
STORAGE_MAX_KEYS | 1000 | Keys per player per scope (the game scope gets 10×) |
MAX_ROOM_PLAYERS / HARD_MAX_ROOM_PLAYERS | 1000 / 5000 | Default room-size cap / the most any game may raise it to |
MAX_ROOMS_PER_GAME | 10000 | Open rooms per game (games can lower it) |
Authorization: Bearer SETUP_KEY (dashboard → game → Setup). The key only reaches that game's configuration, never other games, players or the admin API. GET /api/setup · POST /api/setup/recommend ({profile}) · PUT /api/setup (?dryRun=1) · GET|POST /api/setup/messages (the setup chat with the dashboard; ?wait=60 long-polls for your reply) · POST /api/setup/done ({summary}: closes the setup API, after which settings change only in the dashboard). See MULTIPLAYER.md §0. Rotate the key in the dashboard to revoke it; Re-open setup issues a new key after done.
Admin equivalents: GET|PUT /api/admin/games/:id/setup, GET|POST /api/admin/games/:id/setup/messages (your replies), POST /api/admin/games/:id/setup/reopen.
All routes take Authorization: Bearer ADMIN_TOKEN.
GET /api/admin/overview (includes online players) · POST /api/admin/games/:id/players/:pid/kick ({ban, reason}) · POST /api/admin/games/:id/players/:pid/unban · GET /api/admin/games/:id/leaderboards · GET|DELETE /api/admin/games/:id/leaderboards/:board (?period=day&previous=1; DELETE resets every period, ?config=delete also drops the config) · GET|PUT /api/admin/games/:id/leaderboards/:board/config ({mode, sort, periods, clientWrite, min, max}) · POST /api/admin/games/:id/leaderboards/:board/submit ({player, score, meta}) · DELETE /api/admin/games/:id/leaderboards/:board/players/:pid · GET|PUT /api/admin/games/:id/setup (?dryRun=1) · POST /api/admin/games/:id/setup/recommend · GET|POST /api/admin/games/:id/servers · GET|PATCH|DELETE /api/admin/games/:id/servers/:sid ({name, description, region, tags, maxPlayers, password, visibility, whitelist, queue, motd, type, options, enabled}) · POST /api/admin/games/:id/inbox ({to: id | [ids], type, data}) · GET|POST /api/admin/games · GET|PATCH|DELETE /api/admin/games/:id (PATCH accepts {name, enabled, rotateKey, rotateSetupKey, settings:{allowedOrigins, gameDataWrite, playerDataWrite, lockLeaderboards, inboxClientSend, config, limits, roomTypes, roomDefaults, requireRoomType}}; changing config pushes it to every connected client) · POST /api/admin/games/:id/rooms/:room/close|kick|state · POST /api/admin/games/:id/broadcast · GET|PUT|DELETE /api/admin/games/:id/kv · GET|DELETE /api/admin/games/:id/leaderboards/:board