* **Rujukan Arsitektur:** Dijabarkan lengkap pada **[Stage 7: Network Sync Protocol](wiki/architecture/07_network_sync_protocol.md)**.
Resources
7Install
npx skillscat add yogaprasetya22/mmorpg Install via the SkillsCat registry.
🤖 Authoritative AI Assistant Pair-Programming Playbook
This document defines the strict, high-fidelity engineering directives that every AI pairing agent must read, acknowledge, and adhere to when contributing to this real-time multiplayer MMORPG ecosystem.
[!NOTE]
Before modifying any architecture, GORM database schema, or React Three Fiber pipeline, you MUST study the comprehensive tech stack and data layout blueprints documented in the main Project Blueprint (README.md).
🎯 1. Core Engineering Philosophies
- authoritative Server Architecture: All gameplay mechanics (health pools, coordinate calculations, monster combat state-machines, movement updates) must remain authoritatively controlled on the Go backend server. The React/Three Fiber frontend serves solely as an interpolating visualization shell.
- Pragmatic Persistence: Do not store hardcoded paths, absolute local assets directory strings, or redundant network prefixes in GORM/PostgreSQL records. Save path strings in database columns as clean, portable relative formats (e.g.,
/assets-model/kingdom/wall.glb) and let the runtime load layers prepend absolute remote origins (http://localhost:8080) dynamically. - Zero Regression Standard: Codebase modifications must not introduce compilation warnings, linting failures, or runtime crashes in either the Go server or the Next.js frontend app.
🛠️ 2. Dual-Engine Verification Protocol
After every single modification, addition, or refactoring, and always as the final step before concluding your turn, you MUST run both the authoritative verification and production build commands:
# 1. Verification checks (TypeScript & Backend compiler safety)
make check
# 2. Production build verification (Next.js production bundle & Go executable packaging)
make buildThis ensures that the entire code compiles cleanly, has zero type regressions, and builds successfully into optimized production artifacts without any bundle or asset packing errors. All commands MUST pass with a green state (Exit code: 0 / Zero regression detected) before concluding your turn.
⚡ 3. High-Performance Front-End Standards
To maintain a fluid 60 FPS in complex 3D environments, all high-frequency calculations (e.g., Minimaps, floating health status, spatial tracking grids) MUST adhere to these performance patterns:
- Decouple from React Lifecycle: Do not use standard React state updates (
useState/useContext) inside high-frequency execution loops (such as the main WebSocket stream oruseFrame). Doing so triggers cascading re-renders, causing severe frame drops. - DOM Pooling & Ref caching: Pool DOM elements lazily and manipulate them directly (via standard
ref.current.styleor manual DOM inserts) inside a singlerequestAnimationFrameloop. - Global Exposure: Export low-latency state variables to the global
windowobject (e.g.,window.localPlayerPos) during frame ticks so secondary high-speed overlays can query coordinate states with zero overhead. - Player-Centric Shadow Mapping: Directional lights must dynamically translate and center their shadow camera frustum directly on the local player's coordinate in real time. Downscale the shadow camera frustum bounds from
80mto30mfor razor-sharp shadows at a fraction of the GPU rendering cost. - Adaptive Graphics Quality Scaling: Monitor the rolling FPS rate inside a lightweight
useFrametracker. If performance falls below a critical threshold (e.g., 53 FPS) for more than 3 consecutive seconds (which occurs under multiplayer load or side-by-side browser viewports), programmatically disable screen-space Bloom post-processing and disable the shadow map entirely to guarantee a fluid 60 FPS.
⚡ 4. Low-Latency Go WebSocket Engineering
To maintain sub-millisecond network state propagation in multiplayer environments:
- Direct Synchronous Broadcasts: Avoid spawning temporary Go goroutines or allocating
sync.WaitGroupsynchronization blocks on every broadcast tick to client collections. - Non-Blocking Fan-Out: Use direct, synchronous loops that perform a
select/defaultsend on buffered client channels. Since buffered channel writing is instantaneous (O(1)), this eliminates goroutine scheduling overhead, heap allocations, and garbage collection pauses.
⚡ 5. Authoritative Monster AI & State Control
To maintain reliable server-authoritative combat behavior and prevent player exploits:
- Monster Respawning: Monsters must always respawn back at their original
SpawnPositioncoordinate. Do not overwrite theSpawnPositionfield with the coordinate of their death. - Leash & Tethering Limits: Monsters must have a strict leash distance (e.g., 18.0 units) from their original spawn point. If a monster exceeds this limit during chase or attack, the server must automatically clear their target (
TargetPlayerID = ""), restore their health to full (HP = MaxHP), sync the updated health component to the ECS registry, and transition them back to the"returning"FSM state.
💾 6. Authoritative Database Seeding & Setup
- Idempotency Rule: Seeding routines must be completely safe to execute repeatedly without causing duplicates. Wiping the old dataset before inserting fresh records is mandatory to maintain data cleanliness.
- Command Standardization: All database seed scripts must be linked to target-oriented CLI triggers. Use the authoritative Makefile trigger to run database seed updates:
# Clears and initializes strategic monster configurations make seed-enemy
🌐 7. Live Server & Port Maintenance
- Port Safety: Do not leave stale server processes listening on port
8080(Go GIN) or3000(Next.js). If you alter handlers, middlewares, or models:- Find and cleanly terminate the old process using:
fuser -k 8080/tcp || true - Boot the new engine version to allow seamless schema auto-migrations:
go run cmd/server/main.go
- Find and cleanly terminate the old process using:
- Zero Interruption: Ensure the development server environment is kept healthy so the pair programmer can load the live scene inside their client viewport immediately.
🚀 8. Automated Git Delivery & Conventional Commits
Once the Go backend compiles with zero errors and the frontend TypeScript check passes with zero type-mismatches, you are authorized to stage, commit, and push changes.
A. Stage Changes
Stage only the files that represent functional contributions (avoid tracking irrelevant build binaries or temporary logs):
git add .B. Conventional Commit Guidelines
Draft commit messages using the professional Conventional Commits standard:
feat: ...for new features (e.g.,feat: serve and scan game props dynamically from backend GIN)fix: ...for bug fixes (e.g.,fix: resolve relative path generation in asset scanner to prevent 404)refactor: ...for structural rewrites with no behavioral changeperf: ...for optimizations (e.g., throttling anim loops, instancing mesh groups)
C. Authoritative Remote Sync
Push commits immediately to ensure the remote tracking branch main on GitHub remains synchronized in real time:
git push origin main[!IMPORTANT]
COMPILATION & SINK CHECK ARE NON-NEGOTIABLE. Skipping any phase of this dual validation and deployment workflow is a violation of the development protocol.
⚡ 9. Anti-Lag & GC Performance Guard Rails (CRITICAL)
Untuk mencegah kembalinya masalah Garbage Collection (GC) lag spikes (drop FPS mendadak dari 60 ke 15 FPS selama 1 frame yang dipicu oleh engine pembeku V8 Javascript), aturan ketat performa di bawah ini TIDAK BOLEH DIUBAH/DILANGGAR:
🚫 Pantangan Keras di Render Loop (useFrame)
- Dilarang Alokasi Objek Baru:
- Jangan pernah menulis
new THREE.Vector3(),new THREE.Box3(), atau instansiasi objek apa pun di dalam hookuseFrame()atau fungsi yang dipanggil di dalamnya setiap frame. - Gunakan objek modular/global scratch yang telah dideklarasikan di luar component (seperti
_v3atau_sharedBox3), atau gunakanuseMemosekali saja di level atas.
- Jangan pernah menulis
- Dilarang melakukan Array Spread, Filter, atau Map:
- Menghindari operasi spread
[...array],.filter(), dan.map()di dalam frame loop. Operasi ini membuat array baru di memory heap secara instan 60 kali per detik. - Gunakan array scratch yang dialokasikan di
useRef, bersihkan dengan.length = 0, lalu isi ulang menggunakan manual loop (for).
- Menghindari operasi spread
- Dilarang memicu React State Re-render Berlebihan:
- Jangan memanggil
useState(setX()) dari dalam loopuseFramesecara langsung. Gunakan direct ref manipulation (ref.current.position.set(), dsb) untuk update visual mesh. - Sinkronisasi data ID monster hanya diperbolehkan menulis ke state (
setActiveMonsterIds) jika dan hanya jika data roster benar-benar berubah (changed == true).
- Jangan memanggil
⏱️ Throttling dan Pembatasan Frekuensi (LOD & Adaptive Cap)
- LOD Jarak & Culling:
- Jaga threshold jarak lod (
MONSTER_FAR_SQ&MONSTER_MED_FAR_SQuntuk monster, sertaFAR_SQ&MED_FAR_SQuntuk remote players). Di atas batas ini, mesh wajib di-cull (visible = false) dan animasinya di-pause (activeAction.current.paused = true). - Jangan menghapus adaptive cap density yang membatasi render monster terdekat (cap 5/8/12) dan remote players terdekat (cap 8/12) di situasi keramaian tinggi.
- Jaga threshold jarak lod (
- Penyortiran Teratur:
- Operasi penyortiran jarak monster (
scratch.sort()) dan remote players (scratchPlayerDistances.sort()) sangat berat. Wajib di-throttle di frekuensi maksimal 10Hz (now - lastSortTime.current >= 0.10) menggunakan penanda waktu daristate.clock.elapsedTime.
- Operasi penyortiran jarak monster (
- Object Pooling Terhadap Sorting Scratch:
- Ketika melakukan sorting jarak, dilarang melakukan
.push({ id, distSq })objek baru. Wajib memanfaatkan system pooling (_sortObjPooluntuk monster dan_sortPlayerObjPooluntuk remote players) untuk me-reuse penampung objek koordinat.
- Ketika melakukan sorting jarak, dilarang melakukan
- Set Reuse untuk Visibility Registry:
- Gunakan registry
visiblePlayerIdsRef.current.clear()langsung di dalam frame loop daripada menginstansiasinew Set()setiap frame untuk memantau visibilitas player lain.
- Gunakan registry
🌐 Jaringan dan Background HTTP Polling
- Metode requestIdleCallback:
- Seluruh background HTTP fetch yang berulang (seperti update profil XP/Gold/Level di
ArenaClient.tsx) wajib dijadwalkan menggunakanrequestIdleCallbackdengan toleransi idle budget minimal>5ms. - Jangan pernah menggantinya kembali menggunakan sinkronisasi
setIntervalmentah, karena hal tersebut akan memotong thread utama rendering di tengah jalan dan memicu micro-stuttering.
- Seluruh background HTTP fetch yang berulang (seperti update profil XP/Gold/Level di
- Ambang Batas Lag Spike:
- Ambang deteksi lag spike performa diatur pada batas minimal 50ms. Mengembalikan batas ini ke 33.33ms akan merekam derau micro-stuttering kecil yang tidak relevan dengan kenyamanan bermain user.
🚫 10. DONT-TOUCH ZONE: Sistem Kritis yang Haram Disenggol!
Untuk menjaga kestabilan 60 FPS dan latensi sub-milidetik yang sudah dicapai, arsitektur di bawah ini adalah zona suci yang TIDAK BOLEH diubah atau dimodifikasi tanpa analisis mendalam (lihat panduan pencegahan regresi lengkap di Stage 0: Global Architecture & Context Bootstrap):
1. Metode Deteksi Tanah & Tangga (BVHEcctrl.config)
- Status Saat Ini: Menggunakan
SHAPECASTuntuk deteksi pijakan bawah tanah. - Pantangan: Jangan pernah diubah kembali ke
RAYCASTatauBOTH!- Mengubah ke
RAYCASTakan membuat karakter tersangkut (stuck) di anak tangga karena ray tidak bervolume. - Mengubah ke
BOTHakan memproses kalkulasi BVH ganda yang langsung membuat frame rate client drop parah.
- Mengubah ke
- Rujukan Arsitektur: Dijabarkan lengkap pada Stage 0: Context Bootstrap (Bab 3-A).
2. Decoding WebSocket MessagePack (useWebSocketGame.ts)
- Status Saat Ini: Menggunakan library lokal
@msgpack/msgpacksecara sinkron langsung di main-thread. - Pantangan: Jangan pernah memindahkan kembali proses ini ke Web Worker menggunakan CDN eksternal (
importScripts)!- Browser memblokir pengunduhan skrip eksternal dari CDN luar di dalam blob worker karena aturan ketat Content Security Policy (CSP).
- Decoding lokal sangat cepat (hanya <0.05ms per pass) dan terbukti aman dari error sandbox browser.
- Rujukan Arsitektur: Dijabarkan lengkap pada Stage 7: Network Sync Protocol.
3. Lock-Free Monster State Machine (monster_ai.go)
- Status Saat Ini: Menggunakan string/enum FSM bawaan langsung (
m.AIState) tanpa lock mutex global dan tanpa alokasi heap baru. - Pantangan: Jangan pernah menggunakan kembali library
looplab/fsmatau sejenisnya!- Library eksternal tersebut memicu ribuan alokasi objek per detik pada runtime Go, yang menyebabkan Garbage Collector spikes dan menghabiskan resource server secara sia-sia saat melayani 100+ monster.
- Rujukan Arsitektur: Dijabarkan lengkap pada Stage 0: Context Bootstrap (Bab 3-B).
4. 2D Spatial Hash Grid Server-Side (game_usecase.go & monster_ai.go)
- Status Saat Ini: Menggunakan
SpatialHashGriddengan kerapatan 10.0 unit untuk lookup target terdekat musuh secara $O(1)$. - Pantangan: Jangan pernah mengembalikan logika pencarian target aggro musuh ke loop linier $O(N)$!
- Perbandingan posisi jarak ke seluruh player aktif secara berulang akan menyebabkan CPU overload parah di sisi backend seiring bertambahnya jumlah pemain aktif.
- Rujukan Arsitektur: Dijabarkan lengkap pada Stage 2: Backend Combat Usecase (Langkah 4).
5. Throttle Pengiriman State Player Client (sendPlayerState)
- Status Saat Ini: Pengiriman posisi player ke server dibatasi keras pada frekuensi 20Hz (50ms) dengan sistem deduplikasi perubahan gerakan.
- Pantangan: Jangan pernah menaikkan frekuensi pengiriman ke 60Hz atau mematikan deduplikasi!
- Melakukan hal tersebut akan membanjiri buffer jaringan WebSocket, meningkatkan latensi ping secara drastis, dan menyebabkan karakter bergetar (rubberbanding) di layar pemain lain.
- Rujukan Arsitektur: Dijabarkan lengkap pada Stage 7: Network Sync Protocol.