Membawa game ke dunia online: high-level multiplayer API Godot dengan transport ENet, RPC dan sinkronisasi state lewat MultiplayerSynchronizer, pola authoritative server versus peer-to-peer, hingga dasar lag compensation dan keamanan jaringan agar game multiplayer tidak mudah dipermainkan.

Di episode 12 kalian memoles game dengan animasi, particle, dan shader — sekarang game sudah terasa hidup. Episode 13 menaikkan level: membuat game kalian dimainkan bersama. Kita membangun multiplayer dengan high-level API Godot yang menyembunyikan kompleksitas socket TCP/UDP, sehingga kalian lebih banyak menulis logika game daripada protokol jaringan.
Roadmap episode ini: mengenal high-level multiplayer API dan transport ENet, membuat lobby sederhana dengan host dan join, memakai RPC untuk memanggil fungsi lintas mesin, sinkronisasi state dengan MultiplayerSynchronizer, lalu menutup dengan pola authoritative server versus peer-to-peer serta dasar lag compensation dan keamanan jaringan.
Godot punya high-level multiplayer API: satu set node dan metode yang menangani koneksi, serialisasi, dan routing secara otomatis. Kalian tidak perlu menulis byte buffer sendiri — cukup definisikan data apa yang dikirim, dan Godot mengurusnya.
Di balik layar, transport defaultnya adalah ENet, pustaka jaringan berbasis UDP dengan lapisan kehandalan. ENet memberikan pengiriman yang cepat seperti UDP sekaligus kemampuan untuk memastikan pesan penting sampai seperti TCP. Di Godot 4, kelas yang dipakai adalah ENetMultiplayerPeer. (Di Godot 3, kelas ini bernama NetworkedMultiplayerENet — kalau kalian membaca tutorial lama, itu nama lamanya.)
Komponen intinya tiga: MultiplayerAPI (otak routing), MultiplayerPeer (transport, diisi ENet), dan node pembantu seperti MultiplayerSynchronizer dan MultiplayerSpawner untuk sinkronisasi otomatis.
Pola paling dasar adalah satu pemain menjadi host (server sekaligus client) dan pemain lain join ke alamatnya. Buatlah sebuah node autoload bernama Net agar seluruh game bisa mengakses koneksi:
func jadi_host(port: int = 9999) -> void:
var peer := ENetMultiplayerPeer.new()
peer.create_server(port, 4)
multiplayer.multiplayer_peer = peer
func on_peer_connected(id: int) -> void:
print("Pemain masuk dengan ID ", id)func gabung(ip: String, port: int = 9999) -> void:
var peer := ENetMultiplayerPeer.new()
peer.create_client(ip, port)
multiplayer.multiplayer_peer = peerSetiap client diidentifikasi dengan peer ID: host selalu 1, dan client diberi ID unik setelah join. ID inilah yang dipakai untuk mengarahkan pesan ke pemain tertentu. Hubungkan signal peer_connected dan peer_disconnected dari multiplayer untuk menangkap pemain yang masuk dan keluar.
Info
Sinyal koneksi (peer_connected) hanya terpanggil pada host. Client tahu koneksinya berhasil lewat MultiplayerAPI.connection_succeeded. Biasakan mengecek is_server() sebelum menambahkan pemain ke daftar game.
RPC (Remote Procedure Call) adalah cara memanggil fungsi di mesin lain seolah-olah lokal. Di Godot 4, sebuah fungsi ditandai dengan anotasi @rpc, lalu dipanggil lewat rpc() atau rpc_id():
@rpc("any_peer", "call_local")
func muat_level(level: int) -> void:
get_tree().change_scene_to_file("res://levels/level_%d.tscn" % level)
func minta_ganti_level(level: int) -> void:
rpc("muat_level", level)@rpc menerima beberapa mode: any_peer (siapa pun boleh memanggil) versus authority (hanya authority yang boleh), call_local (pemanggil ikut mengeksekusi), dan reliable (pakai transport handal) versus unreliable. Untuk posisi yang diperbarui setiap frame, gunakan unreliable; untuk data penting seperti damage, gunakan reliable.
Menebar rpc untuk setiap perubahan posisi akan membanjiri jaringan. Untuk state yang berubah terus-menerus, Godot 4 menyediakan MultiplayerSynchronizer: node yang mendaftarkan properti node lain, lalu mengirim nilai terbarunya ke peer lain secara otomatis beberapa kali per detik.
Letakkan MultiplayerSynchronizer sebagai anak dari node pemain, daftarkan node target di property root_path, lalu daftarkan properti yang ingin disinkronkan:
$MultiplayerSynchronizer.root_path = get_path()
$MultiplayerSynchronizer.update_interval = 0.05
$MultiplayerSynchronizer.replication_configUntuk objek yang dibuat saat runtime — peluru, musuh spawn — pasangkan MultiplayerSpawner: setiap instance yang ditambahkan ke scene tree di mesin pembuat otomatis dibuat ulang di mesin lain. Dengan Spawner + Synchronizer, sebagian besar game action bisa disinkronkan tanpa menulis kode jaringan manual.
Pertanyaan arsitektur paling penting: siapa yang menentukan kebenaran game? Ada dua pola besar:
Di Godot, pola authoritative server berarti kode fisika dan damage hanya berjalan di host, sementara client mengirim aksi dan menerima hasil. Contoh kecil: client mengirim perintah "melompat", host yang mengeksekusi:
@rpc("any_peer")
func minta_lompat() -> void:
if multiplayer.is_server():
karakter.melompat()Meskipun peer-to-peer lebih mudah untuk prototipe, bangunlah game kalian dengan pola authoritative server sejak awal — memindahkannya belakangan akan jauh lebih menyakitkan.
Di jaringan nyata, paket tiba dengan latensi — tidak instan. MultiplayerSynchronizer membantu dengan interpolasi, tapi untuk game aksi kalian perlu beberapa teknik lag compensation:
Keamanan menyusul: karena semua data melewati jaringan, kalian tidak bisa mempercayai client. Aturan dasarnya:
unreliable dan update_interval yang wajar.Warning
Godot high-level API bukanlah anti-cheat. API ini mempermudah komunikasi, tetapi semua otoritas tetap bergantung pada desain kalian. Aturan paling sederhana yang menyelamatkan banyak game: "server adalah satu-satunya sumber kebenaran, client hanya pengirim intent".
Episode 13 membawa kalian dari nol ke multiplayer fungsional: ENetMultiplayerPeer sebagai transport berbasis ENet, pola host dan join dengan peer ID, @rpc untuk memanggil fungsi lintas mesin, MultiplayerSynchronizer dan MultiplayerSpawner untuk sinkronisasi otomatis, perbandingan pola authoritative server versus peer-to-peer, serta dasar lag compensation dan aturan keamanan jaringan.
Inti yang harus dibawa pulang:
ENetMultiplayerPeer; di Godot 3 bernama NetworkedMultiplayerENet.@rpc untuk event yang jarang terjadi dan MultiplayerSynchronizer untuk state yang berubah terus-menerus.is_server() dan memiliki peer ID 1; client dapat ID unik setelah join.Di episode 14, setelah game bisa dimainkan bersama, kalian menghadapi pertanyaan baru: mengapa game terasa berat di mesin kalian? Kita membedah performance & profiling — optimasi draw calls dan batching, physics, profiler bawaan, penggunaan memory dan FPS, sampai optimisasi pada saat export. Game yang cepat bukanlah keberuntungan, melainkan hasil pengukuran.