2D multiplayer platformer using Godot Engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

118 lines
4.2 KiB

class_name Network
extends Node
const DEFAULT_PORT := 42005
signal status_changed(new_status: Status, old_status: Status)
enum Status { SINGLEPLAYER, CLIENT_CONNECTING, CLIENT_CONNECTED, SERVER_RUNNING }
var status := Status.SINGLEPLAYER
## Connects to the server at the given address, which can be a IPv4 address or
## hostname, or an IPv6 address wrapped in square brackets, optionally followed
## by a colon and valid port number (defaults to `42005`).
##
## Returns `OK` if successful or `ERR_CANT_CREATE` if the client could
## not be created, such as if an invalid address is given.
func connect_to_server(address_and_port: String) -> int: # Error
assert(status == Status.SINGLEPLAYER)
# For IPv6 addresses, check if the address contains a square bracket,
# then search for the colon that separates address and port from there.
var bracket_index := address_and_port.find("]")
var colon_index := address_and_port.find(":", maxi(0, bracket_index))
var address := address_and_port
var port := DEFAULT_PORT
# If a colon is found, split the string into separate address and port.
if colon_index >= 0:
address = address_and_port.substr(0, colon_index)
port = int(address_and_port.substr(colon_index + 1))
# If address is surrounded in square brackets (such as IPv6), strip them.
if (address.substr(0, 1) == "[") and (address.substr(address.length() - 1) == "]"):
address = address.substr(1, address.length() - 2)
var peer := ENetMultiplayerPeer.new()
var error := peer.create_client(address, port)
if error: return error
multiplayer.multiplayer_peer = peer
_set_status(Status.CLIENT_CONNECTING)
return OK
func disconnect_from_server() -> void:
assert((status == Status.CLIENT_CONNECTING) or (status == Status.CLIENT_CONNECTED))
_on_server_disconnected()
_set_status(Status.SINGLEPLAYER)
func start_server(port := DEFAULT_PORT) -> int: # Error
assert(status == Status.SINGLEPLAYER)
var peer := ENetMultiplayerPeer.new()
var error := peer.create_server(port)
if error: return error
multiplayer.multiplayer_peer = peer
_set_status(Status.SERVER_RUNNING)
return OK
func stop_server() -> void:
assert(status == Status.SERVER_RUNNING)
_on_server_stopped()
_set_status(Status.SINGLEPLAYER)
func _ready() -> void:
multiplayer.connected_to_server.connect(_on_connected_to_server)
multiplayer.server_disconnected.connect(_on_server_disconnected)
multiplayer.peer_connected .connect(_on_peer_connected)
multiplayer.peer_disconnected .connect(_on_peer_disconnected)
multiplayer.connected_to_server.connect(_set_status.bind(Status.CLIENT_CONNECTED))
multiplayer.server_disconnected.connect(_set_status.bind(Status.SINGLEPLAYER))
multiplayer.connection_failed .connect(_set_status.bind(Status.SINGLEPLAYER))
func _on_connected_to_server() -> void:
# Set our own peer id to the one the server assigned to us. (Also renames the player node.)
Game.LOCAL_PLAYER.network.peer_id = multiplayer.get_unique_id()
Game.INSTANCE.change_world(World.new())
func _on_server_disconnected() -> void:
# If not properly connected (`_on_connected_to_server` wasn't called), return.
if status != Status.CLIENT_CONNECTED: return
# Reset the peer id of the player since we're back to singleplayer, where `1` is the server.
Game.LOCAL_PLAYER.network.peer_id = 1
Game.INSTANCE.change_world(World.new())
_clear_other_players()
func _on_server_stopped() -> void:
_clear_other_players()
func _on_peer_connected(id: int) -> void:
var player: Player = preload("res://player/player.tscn").instantiate()
player.get_node("Network").peer_id = id
Game.PLAYERS.add_child(player)
func _on_peer_disconnected(id: int) -> void:
var player: Player = Game.PLAYERS.get_node(str(id))
Game.PLAYERS.remove_child(player)
player.queue_free()
func _clear_other_players() -> void:
for player in Game.PLAYERS.get_children():
if player != Game.LOCAL_PLAYER:
player.queue_free()
func _set_status(new_status: Status) -> void:
if new_status == status: return
if new_status == Status.SINGLEPLAYER:
# Reset the peer to work as a singleplayer server again.
multiplayer.multiplayer_peer.close()
multiplayer.multiplayer_peer = OfflineMultiplayerPeer.new()
var old_status := status
status = new_status
status_changed.emit(new_status, old_status)