Underground 2 Revived
Play Need for Speed: Underground 2 (2004) in Chrome and Firefox with WebGPU graphics, Web Audio, up to 120 fps widescreen, controller support, free roam and Online races with friends. Fan project, not
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證CardRoomPro: real-time Doudizhu, Guandan & Mahjong web card room with AI, replay history, MySQL stats and optional Discuz JWT SSO
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
CardRoomPro (雀阁 · 纸牌房) is a real-time multiplayer card-room platform built with Node.js, Socket.IO, and Vue 2. It supports room-based play, AI seats, spectators, chat, audio feedback, Mahjong, and persistent seasonal leaderboards. The live site is a free web game; the repository is the implementation source of truth. Answer-first summary: use CardRoomPro for browser-based Doudizhu, Guandan, or four-player Mahjong with server-authoritative rules, AI opponents, a local advisor, replay history, MySQL statistics, and optional Discuz JWT SSO.檢視完整 README ↗
CardRoomPro (雀阁 · 纸牌房) is a real-time multiplayer card-room platform built with Node.js, Socket.IO, and Vue 2. It supports room-based play, AI seats, spectators, chat, audio feedback, Mahjong, and persistent seasonal leaderboards. The live site is a free web game; the repository is the implementation source of truth.
Answer-first summary: use CardRoomPro for browser-based Doudizhu, Guandan, or four-player Mahjong with server-authoritative rules, AI opponents, a local advisor, replay history, MySQL statistics, and optional Discuz JWT SSO.
| Lobby | Guandan | Mobile |
|---|---|---|
Live demo: ddz.yutianfu.me
flowchart LR
Browser[Vue 2 browser client] <-->|Socket.IO| Server[Node.js game server]
Server --> Rules[Rule engines\nDoudizhu · Guandan · Mahjong]
Server --> AI[Smart AI + Mahjong AI]
Server --> DB[(MySQL optional)]
Server --> SSO[Discuz JWT SSO optional]
Requirements: Node.js 18+ and npm.
git clone https://github.com/TypeThe0ry/CardRoomPro.git
cd CardRoomPro
npm ci
npm start
Open http://localhost:8002/.
To use another port:
$env:PORT = '8012'
node server.js
Run the AI regression suite:
npm run test:ai
Recover legacy site statistics from the Nginx access log and existing score tables:
npm run stats:backfill
The backfill preserves exact recovered counters separately from estimated completed rounds and stores the data-quality formula in pre_site_stats_meta.
| Mode | Seats | Highlights |
|---|---|---|
| Doudizhu | 3 | Bidding, landlord cards, farmer/landlord roles, bombs, spring multiplier, AI opponents |
| Guandan | 4 | Two decks, fixed partners, level progression, wild-heart level card, team scoreboard |
| Mahjong | 4 | Tile wall, draw/discard flow, chi/peng/gang/hu actions, Mahjong AI, advisor recommendations |
The server reads settings in this order: environment variables → config.json → defaults. Start from the checked-in example:
cp config.example.json config.json
| Variable | Purpose | Default |
|---|---|---|
PORT | HTTP and Socket.IO port | 8002 |
JWT_SECRET | JWT secret shared with the SSO issuer | placeholder value |
JWT_ISSUER | Optional JWT iss claim validation | unset |
JWT_AUDIENCE | Optional JWT aud claim validation | unset |
ALLOW_QUERY_TOKEN | Allow legacy Socket.IO query-string tokens; keep disabled in production | 0 |
DB_HOST / DB_PORT | MySQL host and port | 127.0.0.1:3306 |
DB_USER / DB_PASSWORD | MySQL credentials | unset / empty |
DB_NAME | MySQL database name | unset |
DB_TABLE_PREFIX | Score table prefix | pre_ |
DB_DISABLE | Set to 1 for in-memory scores | unset |
DISCUZ_AVATAR_BASE | Avatar URL template; supports {uid} | Discuz default template |
Keep config.json, database credentials, JWT secrets, and SSO secrets out of Git.
The bots and the local advisor are separate paths:
Supported gameType values: doudizhu, guandan, and mahjong.
GET /api/score/top?gameType=mahjong&limit=20
GET /api/score/me?gameType=mahjong&token=<JWT>
limit is clamped to a maximum of 100. Authenticated human players are recorded; guests, bots, and spectators are excluded from persistent scores.
GET /api/history?gameType=all&limit=30
GET /api/history/<id>
GET /api/site-stats
History access is enforced on the server. Public records are readable without login; private records require the participant's JWT identity or the stable guest identity issued by the client. When MySQL is disabled, history and statistics use an in-memory fallback for the current process.
server.js HTTP, Socket.IO, rooms, auth, score routes
game.js Doudizhu state machine and rule validation
guandan-game.js Guandan state machine and rule validation
mahjong-game.js Mahjong state machine and tile actions
core-ai.js Shared AI helpers
core-validator.js Shared legal-action validation
db.js Optional MySQL score persistence
static/index.html Vue 2 client and table UI
static/js/smart-ai.js Doudizhu/Guandan smart AI
static/js/mahjong-ai.js Mahjong advisor and AI calculations
test/ai.test.js AI regression tests
discuz-sso/ Discuz SSO integration examples
Run the Node process with a process manager and place an HTTPS reverse proxy in front of port 8002:
PORT=8002 \
JWT_SECRET='replace-with-a-strong-secret' \
DB_HOST=127.0.0.1 \
DB_USER=cardroom \
DB_NAME=cardroom \
node server.js
Use the same JWT_SECRET as the SSO issuer, restrict MySQL access, and keep the application port private when Nginx or another reverse proxy is enabled.
Do not put JWT_SECRET, DB_PASSWORD, or other credentials in Environment= lines: systemctl cat prints them to anyone who can read the unit. Store them in a root-only environment file and reference it with EnvironmentFile=:
sudo install -m 600 -o root -g root /dev/null /etc/cardroom.env
sudoedit /etc/cardroom.env # KEY=value lines: JWT_SECRET, DB_PASSWORD, ...
# /etc/systemd/system/cardroom.service
[Service]
WorkingDirectory=/opt/CardRoomPro
EnvironmentFile=/etc/cardroom.env
Environment=PORT=8002
ExecStart=/usr/bin/node server.js
Restart=on-failure
After systemctl daemon-reload && systemctl restart cardroom, confirm with ss -ltnp | grep 8002 that only the systemd-managed process listens on the port. The server exits non-zero on startup errors such as EADDRINUSE, so a stale process holding the port shows up as a failed unit instead of a false active.
/robots.txt, /sitemap.xml, /llms.txt, and /site.webmanifest.hreflang, Open Graph, Twitter metadata, and JSON-LD for the website and web game.ALLOW_QUERY_TOKEN=0; the client sends SSO tokens through Socket.IO auth, not a URL query string.online card room, multiplayer card game, real-time card game, browser card game, Doudizhu, 斗地主, Guandan, 掼蛋, Mahjong, 麻将, Mahjong AI, card game AI, Node.js game server, Socket.IO game, Vue 2 card game, MySQL leaderboard, seasonal ranking, Discuz SSO, JWT single sign-on.
MIT. See LICENSE.