In this tutorial you’ll make a simple chat room in Godot using Godot’s multiplayer API.

Start by making a scene set up like so:

IpEnter is a LineEdit node where you enter the ip of the server, it is initialized to 127.0.0.1, the local ip address of your pc.

LeaveButton is hidden and will be shown when you enter a room.

ChatInput is another LineEdit where you will enter chat messages. ChatDisplay is a TextEdit node with ReadOnly and ShowLineNumbers checked, this will be used to display everyones’ messages.

Now add a script to the root node ChatRoom and set up the following base functions:

extends Control func _ready(): pass func host_room(): pass func join_room(): pass func enter_room(): $SetUp/LeaveButton.show() $SetUp/JoinButton.hide() $SetUp/HostButton.hide() $SetUp/IpEnter.hide() func leave_room(): $SetUp/LeaveButton.hide() $SetUp/JoinButton.show() $SetUp/HostButton.show() $SetUp/IpEnter.show()

Connect button_up signals on each button to their respective functions: LeaveButton to leave_room, JoinButton to join_room, and HostButton to host_room.

Now for the actual multiplayer stuff. Modify the functions with this:

const PORT = 3000 const MAX_USERS = 4 #not including host func _ready(): get_tree().connect("connected_to_server", self, "enter_room") func host_room(): var host = NetworkedMultiplayerENet.new() host.create_server(PORT, MAX_USERS) get_tree().set_network_peer(host) enter_room() func join_room(): var ip = $SetUp/IpEnter.text var host = NetworkedMultiplayerENet.new() host.create_client(ip, PORT) get_tree().set_network_peer(host)

Code explanation: If you host a room, create the server and enter the room. If you join, get the ip address you entered and attempt to enter. If entering is successful, the “connected_to_server” signal is emitted and enter_room is called.

Next let’s add some notifications, like welcome messages or letting other players know you entered.

I add in these lines to easily access the UI:

onready var chat_display = $RoomUI/ChatDisplay onready var chat_input = $RoomUI/ChatInput

Then I add to the end of the host_room() function:

chat_display.text = "Room Created

"

To enter_room():

chat_display.text = "Successfully Joined Room

"

And to leave_room():

chat_display.text += "Left Room

" get_tree().set_network_peer(null

Next, for user enter and exit notifications add this to ready():

get_tree().connect("network_peer_connected", self, "user_entered") get_tree().connect("network_peer_disconnected", self, "user_exited")

Then create the user_entered and user_exited functions:

func user_entered(id): chat_display.text += str(id) + " joined the room

" func user_exited(id): chat_display.text += str(id) + " left the room

"

To test the notifications out you’ll have to export the game so you can run several instances of it.

A unique id is generated for each player when they join, the host is always 1.

Here’s the current code:

extends Control const PORT = 3000 const MAX_USERS = 4 #not including host onready var chat_display = $RoomUI/ChatDisplay onready var chat_input = $RoomUI/ChatInput func _ready(): get_tree().connect("connected_to_server", self, "enter_room") get_tree().connect("network_peer_connected", self, "user_entered") get_tree().connect("network_peer_disconnected", self, "user_exited") func user_entered(id): chat_display.text += str(id) + " joined the room

" func user_exited(id): chat_display.text += str(id) + " left the room

" func host_room(): var host = NetworkedMultiplayerENet.new() host.create_server(PORT, MAX_USERS) get_tree().set_network_peer(host) enter_room() chat_display.text = "Room Created

" func join_room(): var ip = $SetUp/IpEnter.text var host = NetworkedMultiplayerENet.new() host.create_client(ip, PORT) get_tree().set_network_peer(host) func enter_room(): chat_display.text = "Successfully joined room

" $SetUp/LeaveButton.show() $SetUp/JoinButton.hide() $SetUp/HostButton.hide() $SetUp/IpEnter.hide() func leave_room(): get_tree().set_network_peer(null) chat_display.text += "Left Room

" $SetUp/LeaveButton.hide() $SetUp/JoinButton.show() $SetUp/HostButton.show() $SetUp/IpEnter.show()

Now let’s add messaging. I’ll add a send_message and receive_message function and set up _input:

func _input(event): if event is InputEventKey: if event.pressed and event.scancode == KEY_ENTER: send_message() func send_message(): var msg = chat_input.text chat_input.text = "" var id = get_tree().get_network_unique_id() rpc("receive_message", id, msg) sync func receive_message(id, msg): chat_display.text += str(id) + ": " + msg + "

"

send_message() takes your chat input, clears it, then does a remote procedure call (rpc) to receive_message, sending the message and our id.

receive_message has ‘sync’ before ‘func’ which means it gets called on everyone in the network when there’s a rpc to it.

Finally, I’ll add a notification if you get disconnected from the server.

I’ll add to ready()

get_tree().connect("server_disconnected", self, "_server_disconnected")

And create the _server_disconnected() function:

func _server_disconnected(): chat_display.text += "Disconnected from Server

" leave_room()

Here’s the final state of the project:

The final code:

extends Control const PORT = 3000 const MAX_USERS = 4 #not including host onready var chat_display = $RoomUI/ChatDisplay onready var chat_input = $RoomUI/ChatInput func _ready(): get_tree().connect("connected_to_server", self, "enter_room") get_tree().connect("network_peer_connected", self, "user_entered") get_tree().connect("network_peer_disconnected", self, "user_exited") get_tree().connect("server_disconnected", self, "_server_disconnected") func _server_disconnected(): chat_display.text += "Disconnected from Server

" leave_room() func user_entered(id): chat_display.text += str(id) + " joined the room

" func user_exited(id): chat_display.text += str(id) + " left the room

" func host_room(): var host = NetworkedMultiplayerENet.new() host.create_server(PORT, MAX_USERS) get_tree().set_network_peer(host) enter_room() chat_display.text = "Room Created

" func join_room(): var ip = $SetUp/IpEnter.text var host = NetworkedMultiplayerENet.new() host.create_client(ip, PORT) get_tree().set_network_peer(host) func enter_room(): chat_display.text = "Successfully joined room

" $SetUp/LeaveButton.show() $SetUp/JoinButton.hide() $SetUp/HostButton.hide() $SetUp/IpEnter.hide() func leave_room(): get_tree().set_network_peer(null) chat_display.text += "Left Room

" $SetUp/LeaveButton.hide() $SetUp/JoinButton.show() $SetUp/HostButton.show() $SetUp/IpEnter.show() func _input(event): if event is InputEventKey: if event.pressed and event.scancode == KEY_ENTER: send_message() func send_message(): var msg = chat_input.text chat_input.text = "" var id = get_tree().get_network_unique_id() rpc("receive_message", id, msg) sync func receive_message(id, msg): chat_display.text += str(id) + ": " + msg + "

"