extends Node ## Connection Code # Connect the signals. func _ready() -> void: if multiplayer.connected_to_server.connect(_on_connected_ok) != OK: Log.error("FAILED to connect the connected_to_server signal to _on_connected_ok!", "Internal Error: Failed to connect signal.") if multiplayer.connection_failed.connect(close_network) != OK: Log.error("FAILED to connect the connection_failed signal to _on_connected_fail!", "Internal Error: Failed to connect signal.") if multiplayer.server_disconnected.connect(close_network) != OK: Log.error("FAILED to connect the server_disconnected signal to _on_server_disconnected!", "Internal Error: Failed to connect signal.") if multiplayer.peer_disconnected.connect(_on_peer_disconnected) != OK: Log.error("FAILED to connect the peer_disconnected signal to _on_peer_disconnected!", "Internal Error: Failed to connect signal.") # Start the network listener. func start_server() -> Error: var peer: ENetMultiplayerPeer = ENetMultiplayerPeer.new() if peer.create_server(Game.port, Game.max_clients) != OK: Log.warning("Couldn't create the server at port %d!" % Game.port) return FAILED multiplayer.multiplayer_peer = peer Log.info("Created the server at port %d." % Game.port) return OK # Connect to a server. func join_server() -> Error: var peer: ENetMultiplayerPeer = ENetMultiplayerPeer.new() if peer.create_client(Game.ip, Game.port) != OK: Log.warning("Couldn't connect to the server at %s:%d!" % [Game.ip, Game.port]) return FAILED multiplayer.multiplayer_peer = peer Log.info("Connected to the server at %s:%d." % [Game.ip, Game.port]) return OK # Close all network connections. func close_network() -> void: multiplayer.multiplayer_peer = null Log.info("Closed all network connections.") ## Matchmaking Code var mutex: Mutex = Mutex.new() var rooms: Dictionary = {} var peers: Dictionary = {} func join_room() -> void: if join_server() != OK: Log.warning("Failed to connect to sever.") func _on_connected_ok() -> void: if rpc_id(1, "send_roomname", Game.room_name) != OK: Log.warning("Failed to send roomname!") func _on_peer_disconnected(id: int) -> void: mutex.lock() if multiplayer.get_unique_id() == 1: if rooms.has(id): var roomname: String = rooms[id] if !rooms.erase(roomname): Log.warning("The room %s associated with %d doesn't exist in rooms, even though it should!" % [roomname, id]) if !rooms.erase(id): Log.warning("The peer %d doesn't exist in rooms, even though it should!" % id) for peer: int in peers[roomname]: if peer == id: continue if rpc_id(peer, "host_disconnected_message"): Log.warning("Peer %d couldn't be disconnected!" % peer) if !peers.erase(roomname): Log.warning("Room %s couldn't be found, even though it should exist!" % roomname) Log.info("Room %s terminated." % roomname) else: for room: String in peers: for peer: int in peers[room]: if peer == id: var peer_array: Array = peers[room] peer_array.erase(id) peers[room] = peer_array for found_peer: int in peers[room]: if rpc_id(found_peer, "peer_disconnected_message") != OK: Log.warning("Failed to send disconnect message to %d!" % found_peer) mutex.unlock() # The following function sends the roomname selected by the client. @rpc("any_peer", "call_remote", "reliable") func send_roomname(roomname: String) -> void: mutex.lock() if multiplayer.get_unique_id() == 1: if !rooms.has(roomname) and !rooms.has(multiplayer.get_remote_sender_id()): rooms[roomname] = multiplayer.get_remote_sender_id() rooms[multiplayer.get_remote_sender_id()] = roomname peers[roomname] = [multiplayer.get_remote_sender_id()] Log.info("Room %s registered." % roomname) if rpc_id(multiplayer.get_remote_sender_id(), "server_response", 0) != OK: Log.warning("Failed to send elevation reply to %d!") elif peers[roomname] is Array: # For some odd reason, Godot doesn't allow casting peers[roomname] to an Array, but this works? var peer_array: Array = peers[roomname] peer_array.append(multiplayer.get_remote_sender_id()) peers[roomname] = peer_array if rpc_id(multiplayer.get_remote_sender_id(), "server_response", 1) != OK: Log.warning("Failed to send join reply to %d!") Log.debug("Room %s joined by peer %d." % [roomname, multiplayer.get_remote_sender_id()]) else: Log.warning("Peer %d tried to send this client a request meant for the authority!" % multiplayer.get_remote_sender_id()) if rpc_id(multiplayer.get_remote_sender_id(), "server_response", 2) != OK: Log.warning("Failed to send fail reply to %d!") mutex.unlock() # This is the message sent out if the host of the room has left. @rpc("authority", "call_remote", "reliable") func host_disconnected_message() -> void: pass # TODO: Implement this # This is the message sent out if a peer in the room has left. @rpc("authority", "call_remote", "reliable") func peer_disconnected_message() -> void: pass # TODO: Implement this # This is the initial server response, which tells the client what its role is. @rpc("authority", "call_remote", "reliable") func server_response(status: int) -> void: match status: 0: pass # TODO: makes new room manager 1: pass # TODO: makes new room member 2: pass # TODO: server error