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
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)
|
|
|