Get the ingredients.
Install Godot 4.6 or newer and create a temporary project token at the NetPunch home page. The token is shown once and expires automatically.
A step-by-step Godot build
A tiny co-op mission with two players, two guards, a floor button, and one exit. You will start with a project token, connect two native clients, then make the host authoritative over the win condition.
Install Godot 4.6 or newer and create a temporary project token at the NetPunch home page. The token is shown once and expires automatically.
From an authenticated checkout of the private NetPunch repository, copy the supported player addon into the tutorial project. The staging script refuses to replace an unexpected addon link.
cd /path/to/netpunch
bash games/prepare.sh button_buddiesSource access: the repository is private. Use your normal GitHub credentials or an existing local checkout before starting this lesson.
This tutorial uses the hosted NetPunch relay at https://netpunch.it. Your temporary project token authorizes room creation over HTTPS; the server returns each player's UDP credential automatically. You do not need to run a relay for the first playthrough.
API: https://netpunch.it
UDP: netpunch.it:7777Transport: room creation uses HTTPS. Gameplay uses UDP 7777, so native clients must be able to reach the relay.
Button Buddies keeps the room UI deliberately small. The starter reads --api and --project-token, then creates or joins a room from the game menu.
godot --path games/button_buddies -- \
--api=https://netpunch.it \
--project-token=YOUR_PROJECT_TOKENClick Create Game in the first window. NetPunch generates the numeric session ID, join authorization, and UDP member credential. No room number belongs on the command line.
Launch the same command again. In the second window, paste the session ID and select Join Game. Both clients now have a server-assigned peer ID.
godot --path games/button_buddies -- \
--api=https://netpunch.it \
--project-token=YOUR_PROJECT_TOKENPeer 1 is the authority in this tutorial. A client predicts its own movement, but the host applies the input and sends state back to everyone. The important part is the sender check.
@rpc("any_peer", "call_remote", "unreliable_ordered", 1)
func input_command(axis: float) -> void:
if not is_host():
return
var sender := multiplayer.get_remote_sender_id()
if players.has(sender):
apply_input(sender, axis)Use reliable messages for room state and one-shot events. Use unreliable-ordered messages for frequent input and snapshots.
Place the button near the far side of the level. Every host tick checks player overlap. Once one player presses it, the host permanently opens the exit and replicates the state.
if not button_pressed:
for peer_id in players:
if players[peer_id].position.distance_to(BUTTON_POSITION) < 32.0:
button_pressed = true
break
door_open = button_pressedClients render the host's answer. They never decide that the door is open from local overlap alone.
Move two simple guards between fixed points. Contact sends the player back to spawn. When the door is open and every active player is inside the exit zone, the host sends the result event.
if door_open and all_players_at_exit():
mission_complete = true
mission_result.rpc(true)The hosted NetPunch relay is the shortest path. If you want to develop offline or operate your own server, keep the same game and token flow and change only the API URL.
go -C server run ./cmd/netpunch serve \
--tokens=YOUR_PROJECT_TOKENThen launch both clients with --api=http://127.0.0.1:8080. This local command accepts the token as a static development credential and listens on UDP 127.0.0.1:7777.
For an Ubuntu 24.04 host, use a checksum-verified release archive, a DNS name, and an ACME email. Install the host assets, enable public projects in /etc/netpunch/netpunch.json, open TCP 80/443 and UDP 7777, then deploy:
sudo ./netpunch-RELEASE/deploy/scripts/install-host-assets.sh \
--caddy-domain relay.example.com \
--acme-email ops@example.com
sudoedit /etc/netpunch/netpunch.json
sudo ./netpunch-RELEASE/deploy/scripts/deploy-release.sh \
--archive /var/tmp/netpunch-RELEASE-linux-amd64.tar.gz \
--version RELEASEConfig: set relay_public_address to relay.example.com:7777 and set public_projects.enabled to true. Check with sudo /opt/netpunch/current/netpunch check-config --config /etc/netpunch/netpunch.json. Follow docs/deployment/operations.md for firewall, rollback, and backup details.
godot --path games/button_buddies -- \
--api=https://relay.example.com \
--project-token=YOUR_PROJECT_TOKENNative Linux and Windows exports are supported; browser exports are intentionally not, because gameplay uses UDP. If the HTTPS room flow succeeds but the game waits for state, check that UDP port 7777 is reachable.
Room membership, peer IDs, host authority, state replication, an objective, and a win condition. From here, add shooting, prediction, saves, or matchmaking without changing the first connection path.
When the squad gets stuck
Make sure the API URL is the same server that issued the token. Temporary tokens expire and are displayed only once.
Use the numeric session ID, not the project ID. The creator must still have an active room.
Check that both players reached the relay and that UDP 7777 is open. HTTPS alone is not the gameplay transport.
Button Buddies keeps authority on peer 1. Start a new room if the host closes or loses the relay connection.