I have succesfully implement the netfox-noray, but can't connect on itch.io
After succesfully testing the game locally on my network I decided to upload it to Itch.io and attempt to host/join a p2p server. However I always endup with a timeout error (noray error 26)
This is the NetworkManager script that I built by following this documentation.
# NetworkManager.gd - Autoload singleton with netfox-noray support
extends Node
signal peer_connected(id: int)
signal peer_disconnected(id: int)
signal connection_failed()
signal server_disconnected()
var peer: ENetMultiplayerPeer
var is_multiplayer_mode := false
var connected_players := {} # {peer_id: player_data}
# Game synchronization signals
signal game_state_synced(state_data: Dictionary)
signal card_played_remote(player_id: int, card_data: Dictionary, slot_index: int)
signal truco_called_remote(player_id: int, truco_level: int)
signal truco_response_remote(player_id: int, accepted: bool)
# Netfox-noray specific variables
const NORAY_ADDRESS = "tomfol.io"
const NORAY_PORT = 8890
var open_id: String = "" # Public ID that others use to connect
var lobby_code: String = "" # Alias for open_id for compatibility with LobbyMenu
var _is_host: bool = false
var is_connecting: bool = false
func _ready():
`# Connect multiplayer events`
`multiplayer.peer_connected.connect(_on_peer_connected)`
`multiplayer.peer_disconnected.connect(_on_peer_disconnected)`
`multiplayer.connection_failed.connect(_on_connection_failed)`
`multiplayer.server_disconnected.connect(_on_server_disconnected)`
`# Connect noray signals`
`Noray.on_oid.connect(_on_open_id_received)`
`Noray.on_connect_nat.connect(_handle_connect_nat)`
`Noray.on_connect_relay.connect(_handle_connect_relay)`
# --- Host/Join Functions ---
func host_game():
`if is_connecting:`
`print("Already connecting...")`
`return false`
`is_connecting = true`
`_is_host = true`
`# Connect to noray server`
`print("Connecting to noray server at %s:%d" % [NORAY_ADDRESS, NORAY_PORT])`
`var err = await Noray.connect_to_host(NORAY_ADDRESS, NORAY_PORT)`
`if err != OK:`
`print("Failed to connect to noray server: %s" % err)`
`is_connecting = false`
`return false`
`# Register as host`
`print("Registering as host...")`
`Noray.register_host()`
`await Noray.on_pid # Wait for private ID`
`# Register remote address`
`err = await Noray.register_remote()`
`if err != OK:`
`print("Failed to register remote address: %s" % err)`
`is_connecting = false`
`return false`
`# Create server on noray's local port`
`peer = ENetMultiplayerPeer.new()`
`err = peer.create_server(Noray.local_port, 1) # Max 1 client`
`if err != OK:`
`print("Failed to create server on port %d: %s" % [Noray.local_port, err])`
`is_connecting = false`
`return false`
`multiplayer.multiplayer_peer = peer`
`is_multiplayer_mode = true`
`is_connecting = false`
`# Add host as player 0`
`connected_players[1] = {`
`"player_id": 0,`
`"peer_id": 1,`
`"name": "Host",`
`"is_human": true`
`}`
`print("Hosting on port %d" % Noray.local_port)`
`print("Waiting for Open ID...")`
`return true`
func join_game(host_open_id: String, use_relay: bool = true):
`if is_connecting:`
`print("Already connecting...")`
`return false`
`if host_open_id.is_empty():`
`print("Host Open ID cannot be empty")`
`return false`
`is_connecting = true`
`_is_host = false`
`# Connect to noray server`
`print("Connecting to noray server at %s:%d" % [NORAY_ADDRESS, NORAY_PORT])`
`var err = await Noray.connect_to_host(NORAY_ADDRESS, NORAY_PORT)`
`if err != OK:`
`print("Failed to connect to noray server: %s" % err)`
`is_connecting = false`
`return false`
`# Register host (clients also need to register)`
`print("Registering with noray...")`
`Noray.register_host()`
`await Noray.on_pid # Wait for private ID`
`# Register remote address`
`err = await Noray.register_remote()`
`if err != OK:`
`print("Failed to register remote address: %s" % err)`
`is_connecting = false`
`return false`
`# Request connection to host`
`print("Requesting connection to host: %s" % host_open_id)`
`if use_relay:`
`Noray.connect_relay(host_open_id)`
`else:`
`Noray.connect_nat(host_open_id)`
`print("Connection request sent, waiting for response...")`
`return true`
func disconnect_from_game():
`if peer:`
`peer.close()`
`peer = null`
`multiplayer.multiplayer_peer = null`
`is_multiplayer_mode = false`
`_is_host = false`
`is_connecting = false`
`connected_players.clear()`
`open_id = ""`
`lobby_code = "" # Clear lobby_code as well`
`print("Disconnected from multiplayer game")`
func is_server() -> bool:
`return _is_host`
# Legacy method for compatibility with old code
func is_host() -> bool:
`return _is_host`
func get_open_id() -> String:
`return open_id`
func get_local_player_id() -> int:
`if not is_multiplayer_mode:`
`return 0`
`for peer_id in connected_players:`
`if peer_id == multiplayer.get_unique_id():`
`return connected_players[peer_id].player_id`
`return 0`
# --- Noray Signal Handlers ---
func _on_open_id_received(oid: String):
`open_id = oid`
`lobby_code = oid # Set lobby_code for compatibility with LobbyMenu`
`print("Received Open ID: %s" % open_id)`
func _handle_connect_nat(address: String, port: int) -> Error:
`print("Handling NAT connection to %s:%d" % [address, port])`
`return await _handle_connect(address, port)`
func _handle_connect_relay(address: String, port: int) -> Error:
`print("Handling relay connection to %s:%d" % [address, port])`
`return await _handle_connect(address, port)`
func _handle_connect(address: String, port: int) -> Error:
`if _is_host:`
`# Host handshake`
`var enet_peer = multiplayer.multiplayer_peer as ENetMultiplayerPeer`
`var err = await PacketHandshake.over_enet(enet_peer.host, address, port)`
`if err != OK:`
`print("Host handshake failed: %s" % err)`
`return err`
`print("Host handshake successful")`
`else:`
`# Client handshake and connection`
`var udp = PacketPeerUDP.new()`
`udp.bind(Noray.local_port)`
`udp.set_dest_address(address, port)`
`var err = await PacketHandshake.over_packet_peer(udp)`
`udp.close()`
`if err != OK:`
`print("Client handshake failed: %s" % err)`
`is_connecting = false`
`return err`
`print("Client handshake successful, connecting...")`
`# Connect to host`
`peer = ENetMultiplayerPeer.new()`
`err = peer.create_client(address, port, 0, 0, 0, Noray.local_port)`
`if err != OK:`
`print("Failed to create client: %s" % err)`
`is_connecting = false`
`return err`
`multiplayer.multiplayer_peer = peer`
`is_multiplayer_mode = true`
`is_connecting = false`
`print("Connected to host successfully!")`
`return OK`
# --- Multiplayer Events ---
func _on_peer_connected(id: int):
`print("Peer %s connected" % id)`
`if is_server():`
`# Assign player ID 1 to the joining client`
`connected_players[id] = {`
`"player_id": 1,`
`"peer_id": id,`
`"name": "Client",`
`"is_human": true`
`}`
`# Send welcome message and player assignment`
`rpc_id(id, "_receive_player_assignment", 1)`
`rpc_id(id, "_client_greet", "Welcome to the game!")`
`# Notify about successful connection`
`peer_connected.emit(id)`
func _on_peer_disconnected(id: int):
`print("Peer %s disconnected" % id)`
`if connected_players.has(id):`
`connected_players.erase(id)`
`peer_disconnected.emit(id)`
func _on_connection_failed():
`print("Failed to connect to server")`
`is_connecting = false`
`connection_failed.emit()`
func _on_server_disconnected():
`print("Server disconnected")`
`server_disconnected.emit()`
# --- RPC Functions ---
@rpc("authority", "reliable")
func _client_greet(message: String):
`print("[GREETING] %s" % message)`
@rpc("authority", "reliable")
func _receive_player_assignment(player_id: int):
`# Store our player assignment`
`connected_players[multiplayer.get_unique_id()] = {`
`"player_id": player_id,`
`"peer_id": multiplayer.get_unique_id(),`
`"name": "Player %d" % player_id,`
`"is_human": true`
`}`
`print("Assigned as Player %d" % player_id)`
# --- Game Synchronization RPCs ---
@rpc("any_peer", "reliable")
func sync_game_state(state_data: Dictionary):
`print("Game state synced from peer %d" % multiplayer.get_remote_sender_id())`
`game_state_synced.emit(state_data)`
@rpc("any_peer", "reliable")
func play_card_remote(player_id: int, card_name: String, card_value: int, slot_index: int):
`var card_data = {"name": card_name, "value": card_value}`
`print("Card played remotely by player %d" % player_id)`
`card_played_remote.emit(player_id, card_data, slot_index)`
@rpc("any_peer", "reliable")
func call_truco_remote(player_id: int, truco_level: int):
`print("Truco called remotely by player %d (level %d)" % [player_id, truco_level])`
`truco_called_remote.emit(player_id, truco_level)`
@rpc("any_peer", "reliable")
func respond_truco_remote(player_id: int, accepted: bool):
`print("Truco response from player %d: %s" % [player_id, "accepted" if accepted else "rejected"])`
`truco_response_remote.emit(player_id, accepted)`
# --- Utility Functions ---
func get_opponent_peer_id() -> int:
`var local_id = multiplayer.get_unique_id()`
`for peer_id in connected_players:`
`if peer_id != local_id:`
`return peer_id`
`return -1`
func get_player_count() -> int:
`return connected_players.size()`
func is_all_players_connected() -> bool:
`return connected_players.size() >= 2`
# --- Connection Status ---
func get_connection_status() -> String:
`if is_connecting:`
`return "Connecting..."`
`elif not is_multiplayer_mode:`
`return "Not connected"`
`elif is_server():`
`return "Hosting (Open ID: %s)" % open_id`
`else:`
`return "Connected as client"`
I would like to know if I am missing something with my current configuration.
Posted Sep 2, 2025, 3:21 PM UTC