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
实时多人牌局、AI 陪玩、智囊推荐、观战与历史复盘。
Translation pending
GamesJavaScript · HTMLGitHub @TypeThe0ryOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
CardRoomPro: real-time Doudizhu, Guandan & Mahjong web card room with AI, replay history, MySQL stats and optional Discuz JWT SSO
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
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.Read the full 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.