Godot provides low-level networking implementations through ENet for reliable UDP communication and WebSocket for web-based networking. These form the foundation of the high-level multiplayer system.
Most games should use the high-level multiplayer API, but understanding the low-level implementations helps optimize network performance.
var peer = ENetMultiplayerPeer.new()# Create server on port 8080, allow up to 32 clientsvar error = peer.create_server(8080, 32)if error != OK: print("Failed to create server: ", error) return# Configure serverpeer.get_host().compress(ENetConnection.COMPRESS_RANGE_CODER)# Assign to multiplayermultiplayer.multiplayer_peer = peerprint("Server started on port 8080")
var peer = new ENetMultiplayerPeer();// Create server on port 8080, allow up to 32 clientsError error = peer.CreateServer(8080, 32);if (error != Error.Ok){ GD.Print($"Failed to create server: {error}"); return;}// Configure serverpeer.GetHost().Compress(ENetConnection.CompressionMode.RangeCoder);// Assign to multiplayerMultiplayer.MultiplayerPeer = peer;GD.Print("Server started on port 8080");
var peer = ENetMultiplayerPeer.new()# Connect to server at IP address and portvar error = peer.create_client("127.0.0.1", 8080)if error != OK: print("Failed to create client: ", error) return# Configure clientpeer.get_host().compress(ENetConnection.COMPRESS_RANGE_CODER)# Assign to multiplayermultiplayer.multiplayer_peer = peerprint("Connecting to server...")
var peer = new ENetMultiplayerPeer();// Connect to server at IP address and portError error = peer.CreateClient("127.0.0.1", 8080);if (error != Error.Ok){ GD.Print($"Failed to create client: {error}"); return;}// Configure clientpeer.GetHost().Compress(ENetConnection.CompressionMode.RangeCoder);// Assign to multiplayerMultiplayer.MultiplayerPeer = peer;GD.Print("Connecting to server...");
Use the same compression mode on both client and server for compatibility.
ENet supports multiple channels for organizing traffic:
# Set transfer channel and modemultiplayer.multiplayer_peer.transfer_channel = 0 # Default channelmultiplayer.multiplayer_peer.transfer_mode = MultiplayerPeer.TRANSFER_MODE_RELIABLE# Send on specific channelmy_function.rpc_id(peer_id, arg1, arg2)
var peer = WebSocketMultiplayerPeer.new()# Create WebSocket servervar error = peer.create_server(8080)if error != OK: print("Failed to create WebSocket server: ", error) return# Configure TLS (optional, for secure WebSocket)var tls_options = TLSOptions.server( load("res://server.key"), load("res://server.crt"))peer.create_server(8080, "*", tls_options)multiplayer.multiplayer_peer = peerprint("WebSocket server started on port 8080")
var peer = new WebSocketMultiplayerPeer();// Create WebSocket serverError error = peer.CreateServer(8080);if (error != Error.Ok){ GD.Print($"Failed to create WebSocket server: {error}"); return;}Multiplayer.MultiplayerPeer = peer;GD.Print("WebSocket server started on port 8080");
Both ENet and WebSocket implement the PacketPeer interface for raw packet sending:
var peer = ENetMultiplayerPeer.new()peer.create_server(8080, 4)# Get available packet countvar packet_count = peer.get_available_packet_count()if packet_count > 0: # Get packet data var packet = peer.get_packet() # Get packet sender var sender_id = peer.get_packet_peer() # Get transfer mode var mode = peer.get_packet_mode() # Get channel var channel = peer.get_packet_channel() print("Received ", packet.size(), " bytes from ", sender_id)# Send packet to specific peerpeer.set_target_peer(2) # Target peer 2peer.put_packet("Hello".to_utf8_buffer())# Broadcast to allpeer.set_target_peer(0) # 0 = broadcastpeer.put_packet("Hello everyone".to_utf8_buffer())
extends Nodevar tcp_server = TCPServer.new()var clients = []func _ready(): # Start TCP server tcp_server.listen(8080) print("TCP server listening on port 8080")func _process(delta): # Accept new connections if tcp_server.is_connection_available(): var client = tcp_server.take_connection() clients.append(client) print("Client connected") # Process existing connections for client in clients: if client.get_status() == StreamPeerTCP.STATUS_CONNECTED: if client.get_available_bytes() > 0: var data = client.get_data(client.get_available_bytes()) handle_message(client, data[1]) else: clients.erase(client) print("Client disconnected")func handle_message(client: StreamPeerTCP, data: PackedByteArray): print("Received: ", data.get_string_from_utf8()) # Send response var response = "Acknowledged".to_utf8_buffer() client.put_data(response)
# Using UPNP for port forwardingvar upnp = UPNP.new()func setup_upnp(): # Discover gateway var error = upnp.discover() if error != OK: print("UPNP discovery failed") return # Map external port to internal port upnp.add_port_mapping(8080, 8080, "MyGame", "UDP") # Get external IP var external_ip = upnp.query_external_address() print("External IP: ", external_ip)func cleanup_upnp(): upnp.delete_port_mapping(8080, "UDP")
UPNP may not work on all routers. Consider using dedicated relay servers for reliable connectivity.
func monitor_connection(): var peer = multiplayer.multiplayer_peer as ENetMultiplayerPeer if peer: var host = peer.get_host() # Get statistics var peers_count = host.get_peer_count() print("Connected peers: ", peers_count) # Check peer health for peer_id in multiplayer.get_peers(): var peer_info = host.get_peer(peer_id) if peer_info: var rtt = peer_info.get_statistic(ENetPacketPeer.PEER_ROUND_TRIP_TIME) print("Peer ", peer_id, " RTT: ", rtt, "ms")