Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Otoriter Multiplayer Sunucusu (Node + ws)

"Kule Konuşuyor: Node'da Sıfırdan Otoriter Multiplayer Sunucusu" makalesinin çalışan kodu. İstemci nerede olduğunu değil, ne yapmak istediğini gönderir; konumu sunucu hesaplar. Odalar, sabit tick döngüsü (20 Hz), snapshot yayını, girdi doğrulama, token bucket hız limiti ve kopma/yeniden katılma — hepsi TypeScript ile.

Kritik tasarım kararı: oyun mantığı ağı tanımaz. Room, RoomRegistry, TickAccumulator, TokenBucket ve parseClientMessage saf ve senkrondur; WebSocket yalnızca src/server.ts içindeki ince kabukta geçer. Bu yüzden bütün testler tek bir port dinlemeden, tek bir soket açmadan koşar.

Kurulum

npm install

Çalıştırma (demo iki süreç ister)

İki ayrı terminal gerekir:

npm run server   # 1. terminal — ws sunucusu: ws://localhost:8080 · 20 Hz
npm run dev      # 2. terminal — Vite: tarayıcı istemcisi (http://localhost:5173)

Sunucu ayrı bir Node sürecidir; Vite yalnızca tarayıcı istemcisini servis eder. Sunucu kapalıyken sayfa açılır ama "bağlantı: kopuk" yazar ve istemci üstel geri çekilmeyle (0.5s → 1s → 2s … 8s) yeniden bağlanmayı dener.

file:// ile açarsanız boş ekran gelir; mutlaka npm run dev ile açın.

Deneyler

  • İki sekme: http://localhost:5173/ adresini iki sekmede açın. İki daire görürsünüz (kendi karakteriniz mavi, diğerleri gri). Birinde ok tuşlarına / WASD'ye basın, öteki sekmede aynı daire hareket eder (gecikme ~1 tick = 50 ms).
  • Ayrı oda: http://localhost:5173/?room=ikinci — bu sekme diğerlerini görmez, tek daire. Odalar birbirini duymaz.
  • Yeniden katılma: bir sekmeyi kapatıp 10 sn içinde aynı sekmede (aynı sessionStorage) tekrar açın: karakter bıraktığı yerde. 30 sn beklerseniz ortadan ({x:320, y:200}) doğar — RESUME_GRACE_MS = 15_000.
  • Hile denemesi: konsolda soket üzerinden {"type":"input","input":{"seq":1,"x":9999}} gönderin. Hiçbir şey olmaz; parseInput mesajı hareket bilgisi taşımadığı için sessizce düşürür, sunucu log basmaz, bağlantı kopmaz.

Not: bu istemcide prediction yok (bilinçli). Karakteriniz sunucu snapshot'ını bekler; input lag görürsünüz. Tahmin + uzlaştırma katmanı için client-prediction-server-reconciliation projesindeki GameClient buraya doğrudan takılabilir — protokol (Input.seq, lastProcessedSeq) aynıdır.

Test

npm test

16 deterministik test, 4 dosya, ~400 ms. Hiçbiri port dinlemez, soket açmaz, ws import etmez:

  • test/room.test.ts (5) — katılma/ayrılma, girdinin tick'te uygulanması, lastProcessedSeq yalnızca simüle edileni gösterir, tekrar/geri giden seq reddi, kuyruk tavanı + bilinmeyen oyuncu.
  • test/registry.test.ts (4) — boş oda temizliği, oda izolasyonu, grace içinde resume, süresi dolmuş/bilinmeyen token.
  • test/tick.test.ts (3) — 100 ms = 2 tick, drift telafisi (61 ms → sonraki bekleme 39 ms), ölüm sarmalı koruması.
  • test/guards.test.ts (4) — token bucket, geçerli girdi, çöp reddi, konum iddiasının yok sayılması.

Bench

npm run bench

Tek oda, 2000 tick, oyuncu başına tick'te 3 girdi; Math.random yok. Tick maliyetini ve snapshot boyutunu oyuncu sayısına karşı ölçer. Örnek çıktı (Node 22):

tick bütçesi: 50 ms (20 Hz) · tick başına oyuncu başına 3 girdi (tavan 5)
oyuncu | ms/tick | bütçe % | snapshot (byte) | 20 Hz yayın (KB/s)
-------|---------|---------|-----------------|-------------------
     1 |  0.0016 |   0.003 |             130 |                2.5
     2 |  0.0016 |   0.003 |             196 |                7.7
     8 |  0.0039 |   0.008 |             573 |               89.5
    32 |  0.0122 |   0.024 |            2101 |             1313.0
   128 |  0.0489 |   0.098 |            8250 |            20624.1
   512 |  0.1876 |   0.375 |           33117 |           331169.0

Simülasyon bedava (512 oyuncuda bile tick bütçesinin binde dördü); patlayan taraf yayın trafiği, çünkü tam snapshot maliyeti oyuncu sayısının karesiyle büyür. Delta compression ve area of interest tam olarak bunun için var.

Diğer komutlar

npm run typecheck   # tsc --noEmit
npm run build       # tsc && vite build
npm run preview     # üretim derlemesini servis et
npm run scratch     # makaledeki minimal 3 olaylı ws örneği (8080)

Dosya yapısı

src/
  sim.ts               # PlayerState, Input, SIM_DT, SPEED, WORLD, saf step() + clamp
  room.ts              # Room: girdi kuyruğu, tick, Snapshot, lastProcessedSeq
  registry.ts          # RoomRegistry: join/leave/resume/sweep/tickAll, boş oda temizliği
  tick.ts              # TickAccumulator (drift telafisi) + startTickLoop (enjekte saat)
  validate.ts          # parseInput / parseClientMessage — gelen her byte düşman
  ratelimit.ts         # TokenBucket
  server.ts            # ws katmanı: connection/message/close + snapshot yayını
  bench-cli.ts         # tick maliyeti ve snapshot boyutu ölçümü
  client/net.ts        # üstel geri çekilmeli yeniden bağlanma + Connection
  client/main.ts       # tarayıcı istemcisi: girdi üretimi (60 Hz), çizim, durum
  scratch/minimal-ws.ts# makaledeki en küçük ws örneği
test/
  room.test.ts  registry.test.ts  tick.test.ts  guards.test.ts
index.html             # Vite giriş noktası (canvas 640x400)

Lisans

MIT

About

Authoritative multiplayer game server in Node.js and ws: room management, fixed tick loop, snapshot broadcast, input validation, and token-bucket rate limiting.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages